1212#include <sof/audio/format.h>
1313#include <sof/audio/pipeline.h>
1414#include <sof/audio/ipc-config.h>
15+ #include <module/audio/source_api.h>
16+ #include <module/audio/sink_api.h>
1517#include <sof/common.h>
1618#include <rtos/panic.h>
1719#include <sof/ipc/msg.h>
@@ -36,29 +38,39 @@ LOG_MODULE_REGISTER(mfcc, CONFIG_SOF_LOG_LEVEL);
3638
3739SOF_DEFINE_REG_UUID (mfcc );
3840
39- __cold_rodata const struct mfcc_func_map mfcc_fm [] = {
41+ /** \brief Source/sink API based source copy function map. */
42+ struct mfcc_source_func_map {
43+ uint8_t source ;
44+ mfcc_source_func func ;
45+ };
46+
47+ __cold_rodata static const struct mfcc_source_func_map mfcc_sfm [] = {
4048#if CONFIG_FORMAT_S16LE
41- {SOF_IPC_FRAME_S16_LE , mfcc_s16_default },
42- #endif /* CONFIG_FORMAT_S16LE */
49+ {SOF_IPC_FRAME_S16_LE , mfcc_source_copy_s16 },
50+ #endif
4351#if CONFIG_FORMAT_S24LE
44- {SOF_IPC_FRAME_S24_4LE , mfcc_s24_default },
45- #endif /* CONFIG_FORMAT_S24LE */
52+ {SOF_IPC_FRAME_S24_4LE , mfcc_source_copy_s24 },
53+ #endif
4654#if CONFIG_FORMAT_S32LE
47- {SOF_IPC_FRAME_S32_LE , mfcc_s32_default },
48- #endif /* CONFIG_FORMAT_S32LE */
55+ {SOF_IPC_FRAME_S32_LE , mfcc_source_copy_s32 },
56+ #endif
4957};
5058
51- static mfcc_func mfcc_find_func (enum sof_ipc_frame source_format ,
52- enum sof_ipc_frame sink_format ,
53- const struct mfcc_func_map * map ,
54- int n )
59+ /**
60+ * \brief Look up the source copy function for a given input format.
61+ *
62+ * \param[in] source_format SOF IPC frame format of the input stream.
63+ *
64+ * \return Pointer to the matching mfcc_source_func, or NULL if the
65+ * format is not supported in this build.
66+ */
67+ static mfcc_source_func mfcc_find_source_func (enum sof_ipc_frame source_format )
5568{
5669 int i ;
5770
58- /* Find suitable processing function from map. */
59- for (i = 0 ; i < n ; i ++ ) {
60- if (source_format == map [i ].source )
61- return map [i ].func ;
71+ for (i = 0 ; i < ARRAY_SIZE (mfcc_sfm ); i ++ ) {
72+ if (source_format == mfcc_sfm [i ].source )
73+ return mfcc_sfm [i ].func ;
6274 }
6375
6476 return NULL ;
@@ -68,6 +80,16 @@ static mfcc_func mfcc_find_func(enum sof_ipc_frame source_format,
6880 * End of MFCC setup code. Next the standard component methods.
6981 */
7082
83+ /**
84+ * \brief MFCC module init callback.
85+ *
86+ * Allocates the component private data and the configuration blob
87+ * handler used to receive the MFCC configuration from user space.
88+ *
89+ * \param[in,out] mod Processing module being initialized.
90+ *
91+ * \return 0 on success, -ENOMEM on allocation failure.
92+ */
7193static int mfcc_init (struct processing_module * mod )
7294{
7395 struct module_data * md = & mod -> priv ;
@@ -92,6 +114,16 @@ static int mfcc_init(struct processing_module *mod)
92114 return 0 ;
93115}
94116
117+ /**
118+ * \brief MFCC module free callback.
119+ *
120+ * Releases the IPC notification message, configuration blob handler,
121+ * runtime buffers and the private data structure.
122+ *
123+ * \param[in,out] mod Processing module being freed.
124+ *
125+ * \return 0 on success.
126+ */
95127static int mfcc_free (struct processing_module * mod )
96128{
97129 struct mfcc_comp_data * cd = module_get_private_data (mod );
@@ -106,27 +138,77 @@ static int mfcc_free(struct processing_module *mod)
106138}
107139
108140
141+ /**
142+ * \brief Source/sink API based process function for MFCC.
143+ *
144+ * Reads input audio from sof_source, runs the STFT/Mel/DCT stage, and
145+ * delegates output formatting and commit handling to mfcc_common.c.
146+ *
147+ * \param[in,out] mod Processing module.
148+ * \param[in,out] sources Source array; only sources[0] is used.
149+ * \param[in] num_of_sources Number of sources (must be 1).
150+ * \param[in,out] sinks Sink array; only sinks[0] is used.
151+ * \param[in] num_of_sinks Number of sinks (must be 1).
152+ *
153+ * \return 0 on success, -ENODATA if no input frames are available,
154+ * or a negative error code from the STFT or output stages.
155+ */
109156static int mfcc_process (struct processing_module * mod ,
110- struct input_stream_buffer * input_buffers , int num_input_buffers ,
111- struct output_stream_buffer * output_buffers , int num_output_buffers )
157+ struct sof_source * * sources , int num_of_sources ,
158+ struct sof_sink * * sinks , int num_of_sinks )
112159{
113160 struct mfcc_comp_data * cd = module_get_private_data (mod );
114- struct audio_stream * source = input_buffers -> data ;
115- struct audio_stream * sink = output_buffers -> data ;
116- int frames = input_buffers -> size ;
161+ struct comp_dev * dev = mod -> dev ;
162+ struct mfcc_state * state = & cd -> state ;
163+ bool pending ;
164+ size_t source_avail ;
165+ int frames ;
166+ int num_ceps ;
167+
168+ comp_dbg (dev , "start" );
169+
170+ /* In compress mode, retry pending output first and avoid producing
171+ * new frames until previous frame has been committed. In legacy
172+ * mode, pending output is held in a dedicated staging buffer
173+ * (state->out_stage) that STFT does not touch, so input processing
174+ * can continue while the previous period is drained.
175+ */
176+ pending = state -> header_pending || state -> out_remain > 0 ;
177+ if (cd -> config -> compress_output && pending )
178+ return mfcc_process_output (mod , cd , sources , sinks , 0 , 0 );
117179
118- comp_dbg (mod -> dev , "start" );
180+ source_avail = source_get_data_frames_available (sources [0 ]);
181+ frames = MIN (source_avail , cd -> max_frames );
182+ if (frames == 0 )
183+ return - ENODATA ;
119184
120- frames = MIN ( frames , cd -> max_frames );
121- cd -> mfcc_func ( mod , input_buffers , output_buffers , frames );
185+ /* Copy input audio from source to MFCC internal circular buffer */
186+ cd -> source_func ( sources [ 0 ], & state -> buf , & state -> emph , frames , state -> source_channel );
122187
123- /* TODO: use module_update_buffer_position() from #6194 */
124- input_buffers -> consumed += audio_stream_frame_bytes (source ) * frames ;
125- output_buffers -> size += audio_stream_frame_bytes (sink ) * frames ;
126- comp_dbg (mod -> dev , "done" );
127- return 0 ;
188+ /* Run STFT and Mel/DCT processing */
189+ num_ceps = mfcc_stft_process (mod , cd );
190+ if (num_ceps < 0 )
191+ return num_ceps ;
192+
193+ return mfcc_process_output (mod , cd , sources , sinks , num_ceps , frames );
128194}
129195
196+ /**
197+ * \brief MFCC module prepare callback.
198+ *
199+ * Validates the source/sink connection, reads the configuration blob,
200+ * initializes the MFCC processing state via mfcc_setup(), selects the
201+ * input copy function for the source frame format, and prepares the
202+ * VAD switch control notification when enabled.
203+ *
204+ * \param[in,out] mod Processing module being prepared.
205+ * \param[in,out] sources Source array; only sources[0] is used.
206+ * \param[in] num_of_sources Number of sources (must be 1).
207+ * \param[in,out] sinks Sink array; only sinks[0] is used.
208+ * \param[in] num_of_sinks Number of sinks (must be 1).
209+ *
210+ * \return 0 on success or a negative error code.
211+ */
130212static int mfcc_prepare (struct processing_module * mod ,
131213 struct sof_source * * sources , int num_of_sources ,
132214 struct sof_sink * * sinks , int num_of_sinks )
@@ -172,13 +254,21 @@ static int mfcc_prepare(struct processing_module *mod,
172254 return - EINVAL ;
173255 }
174256
175- cd -> mfcc_func = mfcc_find_func (source_format , sink_format , mfcc_fm , ARRAY_SIZE ( mfcc_fm ) );
176- if (!cd -> mfcc_func ) {
177- comp_err (dev , "No proc func" );
257+ cd -> source_func = mfcc_find_source_func (source_format );
258+ if (!cd -> source_func ) {
259+ comp_err (dev , "No source func" );
178260 mfcc_free_buffers (mod );
179261 return - EINVAL ;
180262 }
181263
264+ cd -> source_format = source_format ;
265+
266+ if (cd -> config -> compress_output )
267+ comp_info (dev , "compress PCM output mode enabled" );
268+
269+ if (cd -> config -> enable_dtx && !cd -> config -> compress_output )
270+ comp_warn (dev , "enable_dtx ignored in normal PCM mode, only applies to compress" );
271+
182272 /* Initialize VAD switch control notification if enabled */
183273 if (cd -> config -> enable_vad && cd -> config -> update_controls ) {
184274 if (!cd -> msg ) {
@@ -194,6 +284,17 @@ static int mfcc_prepare(struct processing_module *mod,
194284 return 0 ;
195285}
196286
287+ /**
288+ * \brief MFCC module reset callback.
289+ *
290+ * Frees runtime buffers (NULLing their pointers) so a subsequent
291+ * mfcc_prepare() can re-allocate cleanly. The configuration blob
292+ * handler and IPC notification message are preserved.
293+ *
294+ * \param[in,out] mod Processing module being reset.
295+ *
296+ * \return 0 on success.
297+ */
197298static int mfcc_reset (struct processing_module * mod )
198299{
199300 struct mfcc_comp_data * cd = module_get_private_data (mod );
@@ -206,7 +307,7 @@ static int mfcc_reset(struct processing_module *mod)
206307 mfcc_free_buffers (mod );
207308
208309 /* Reset to similar state as init() */
209- cd -> mfcc_func = NULL ;
310+ cd -> source_func = NULL ;
210311 return 0 ;
211312}
212313
@@ -215,7 +316,7 @@ static const struct module_interface mfcc_interface = {
215316 .free = mfcc_free ,
216317 .set_configuration = mfcc_set_config ,
217318 .get_configuration = mfcc_get_config ,
218- .process_audio_stream = mfcc_process ,
319+ .process = mfcc_process ,
219320 .prepare = mfcc_prepare ,
220321 .reset = mfcc_reset ,
221322};
0 commit comments