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_fmt ;
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_fmt )
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,76 @@ 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, or a negative error code from the STFT or output stages.
154+ */
109155static 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 )
156+ struct sof_source * * sources , int num_of_sources ,
157+ struct sof_sink * * sinks , int num_of_sinks )
112158{
113159 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 ;
160+ struct comp_dev * dev = mod -> dev ;
161+ struct mfcc_state * state = & cd -> state ;
162+ bool pending ;
163+ size_t source_avail ;
164+ int frames ;
165+ int num_ceps ;
166+
167+ comp_dbg (dev , "start" );
168+
169+ /* In compress mode, retry pending output first and avoid producing
170+ * new frames until previous frame has been committed. In legacy
171+ * mode, pending output is held in a dedicated staging buffer
172+ * (state->out_stage) that STFT does not touch, so input processing
173+ * can continue while the previous period is drained.
174+ */
175+ pending = state -> header_pending || state -> out_remain > 0 ;
176+ if (cd -> config -> compress_output && pending )
177+ return mfcc_process_output (mod , cd , sources , sinks , 0 , 0 );
117178
118- comp_dbg (mod -> dev , "start" );
179+ source_avail = source_get_data_frames_available (sources [0 ]);
180+ frames = MIN (source_avail , cd -> max_frames );
181+ if (!frames )
182+ return 0 ;
119183
120- frames = MIN ( frames , cd -> max_frames );
121- cd -> mfcc_func ( mod , input_buffers , output_buffers , frames );
184+ /* Copy input audio from source to MFCC internal circular buffer */
185+ cd -> source_func ( sources [ 0 ], & state -> buf , & state -> emph , frames , state -> source_channel );
122186
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 ;
187+ /* Run STFT and Mel/DCT processing */
188+ num_ceps = mfcc_stft_process (mod , cd );
189+ if (num_ceps < 0 )
190+ return num_ceps ;
191+
192+ return mfcc_process_output (mod , cd , sources , sinks , num_ceps , frames );
128193}
129194
195+ /**
196+ * \brief MFCC module prepare callback.
197+ *
198+ * Validates the source/sink connection, reads the configuration blob,
199+ * initializes the MFCC processing state via mfcc_setup(), selects the
200+ * input copy function for the source frame format, and prepares the
201+ * VAD switch control notification when enabled.
202+ *
203+ * \param[in,out] mod Processing module being prepared.
204+ * \param[in,out] sources Source array; only sources[0] is used.
205+ * \param[in] num_of_sources Number of sources (must be 1).
206+ * \param[in,out] sinks Sink array; only sinks[0] is used.
207+ * \param[in] num_of_sinks Number of sinks (must be 1).
208+ *
209+ * \return 0 on success or a negative error code.
210+ */
130211static int mfcc_prepare (struct processing_module * mod ,
131212 struct sof_source * * sources , int num_of_sources ,
132213 struct sof_sink * * sinks , int num_of_sinks )
@@ -172,13 +253,21 @@ static int mfcc_prepare(struct processing_module *mod,
172253 return - EINVAL ;
173254 }
174255
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" );
256+ cd -> source_func = mfcc_find_source_func (source_format );
257+ if (!cd -> source_func ) {
258+ comp_err (dev , "No source func" );
178259 mfcc_free_buffers (mod );
179260 return - EINVAL ;
180261 }
181262
263+ cd -> source_format = source_format ;
264+
265+ if (cd -> config -> compress_output )
266+ comp_info (dev , "compress PCM output mode enabled" );
267+
268+ if (cd -> config -> enable_dtx && !cd -> config -> compress_output )
269+ comp_warn (dev , "enable_dtx ignored in normal PCM mode, only applies to compress" );
270+
182271 /* Initialize VAD switch control notification if enabled */
183272 if (cd -> config -> enable_vad && cd -> config -> update_controls ) {
184273 if (!cd -> msg ) {
@@ -194,6 +283,17 @@ static int mfcc_prepare(struct processing_module *mod,
194283 return 0 ;
195284}
196285
286+ /**
287+ * \brief MFCC module reset callback.
288+ *
289+ * Frees runtime buffers (NULLing their pointers) so a subsequent
290+ * mfcc_prepare() can re-allocate cleanly. The configuration blob
291+ * handler and IPC notification message are preserved.
292+ *
293+ * \param[in,out] mod Processing module being reset.
294+ *
295+ * \return 0 on success.
296+ */
197297static int mfcc_reset (struct processing_module * mod )
198298{
199299 struct mfcc_comp_data * cd = module_get_private_data (mod );
@@ -206,7 +306,7 @@ static int mfcc_reset(struct processing_module *mod)
206306 mfcc_free_buffers (mod );
207307
208308 /* Reset to similar state as init() */
209- cd -> mfcc_func = NULL ;
309+ cd -> source_func = NULL ;
210310 return 0 ;
211311}
212312
@@ -215,7 +315,7 @@ static const struct module_interface mfcc_interface = {
215315 .free = mfcc_free ,
216316 .set_configuration = mfcc_set_config ,
217317 .get_configuration = mfcc_get_config ,
218- .process_audio_stream = mfcc_process ,
318+ .process = mfcc_process ,
219319 .prepare = mfcc_prepare ,
220320 .reset = mfcc_reset ,
221321};
0 commit comments