Skip to content

Commit 41e9f2b

Browse files
committed
audio: module_adapter: support sinkless IADK modules
Detector endpoints can consume input without a connected audio sink. Their process callback was skipped, prepare rejected the graph, and DP period calculation left the deadline at UINT_MAX. Allow sink/source modules without a sink, derive their DP period from the source IBS, and pass at most one IBS to each process call. A module without a sink still needs at least one connected source. Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
1 parent f8908cc commit 41e9f2b

4 files changed

Lines changed: 37 additions & 5 deletions

File tree

src/audio/module_adapter/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ sequenceDiagram
104104
deactivate DP
105105
```
106106

107+
A sinkless DP module derives its period from the first source's
108+
`min_available` value (its IBS) and audio format. This schedules input-only
109+
detectors according to data arrival; a zero or otherwise invalid period is
110+
rejected by the normal minimum-period check during prepare.
111+
107112
## Error Handling and Memory Sandboxing
108113

109114
* **Sandboxing (`mod_balloc_align`, `z_impl_mod_fast_get`, `z_impl_mod_free`)**: Since third-party DSP code is treated as semi-untrusted in memory lifetimes, module allocations grab slices from a dedicated component `dp_heap_user` heap instead of the global system heap (`mod_heap_info`). The wrapper automatically prunes leaked objects (`mod_free_all(mod)`) during teardown by keeping an `objpool` of all resource containers.

src/audio/module_adapter/iadk/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ A significant task of `IadkModuleAdapter_Process` is converting SOF's underlying
8989

9090
Instead of letting the module directly touch the SOF `comp_buffer` (which could change with SOF version updates), the adapter uses the abstraction APIs (`source_get_data` / `sink_get_buffer`) and wraps them:
9191

92-
1. Request raw continuous memory pointers from `source_get_data()`.
92+
1. Limit each input to one source `min_available` portion (one IBS), then
93+
request its continuous memory pointer from `source_get_data()`.
9394
2. Construct an `intel_adsp::InputStreamBuffer` pointing to that continuous memory chunk.
9495
3. Call the IADK `processing_module_.Process()`.
9596
4. Release precisely the amount of consumed data using `source_release_data()`.
97+
98+
Input-only detector endpoints are processed even when no audio sink is
99+
connected. Their output descriptors remain empty, so the module can consume
100+
and inspect each IBS without producing downstream audio.

src/audio/module_adapter/iadk/iadk_module_adapter.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ int IadkModuleAdapter::IadkModuleAdapter_Process(struct sof_source **sources,
4646
{
4747
int ret = 0;
4848

49-
if ((num_of_sources > 0) && (num_of_sinks > 0)) {
49+
if (num_of_sources > 0) {
5050
intel_adsp::InputStreamBuffer input_stream_buffers[INPUT_PIN_COUNT];
5151
intel_adsp::OutputStreamBuffer output_stream_buffers[OUTPUT_PIN_COUNT];
5252
for (int i = 0; i < (int)num_of_sources; i++) {
@@ -55,6 +55,11 @@ int IadkModuleAdapter::IadkModuleAdapter_Process(struct sof_source **sources,
5555

5656
intel_adsp::InputStreamFlags flags = {};
5757
i_size = source_get_data_available(sources[i]);
58+
size_t min_available = source_get_min_available(sources[i]);
59+
60+
if (min_available && i_size > min_available)
61+
i_size = min_available;
62+
5863
ret = source_get_data(sources[i], i_size, (const void **)&input,
5964
(const void **)&input_start, &input_end);
6065
if (ret != 0)
@@ -255,4 +260,3 @@ void* operator new(size_t size, intel_adsp::OutputStreamBuffer* placeholder) thr
255260
return placeholder;
256261
}
257262
#endif
258-

src/audio/module_adapter/module_adapter.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,18 @@ static void module_adapter_calculate_dp_period(struct comp_dev *dev)
366366

367367
}
368368

369+
/* Sinkless modules derive their deadline from one input buffer. */
370+
if (period == UINT32_MAX && mod->num_of_sources > 0) {
371+
size_t frame_bytes = source_get_frame_bytes(mod->sources[0]);
372+
unsigned int rate = source_get_rate(mod->sources[0]);
373+
374+
if (frame_bytes && rate)
375+
period = 1000000ULL * source_get_min_available(mod->sources[0]) /
376+
(frame_bytes * rate);
377+
else
378+
period = 0;
379+
}
380+
369381
dev->period = period;
370382
}
371383
#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */
@@ -473,12 +485,18 @@ int module_adapter_prepare(struct comp_dev *dev)
473485
* Hence check for NULL.
474486
*/
475487
sink = comp_dev_get_first_data_consumer(dev);
476-
if (!sink) {
488+
if (!sink && !IS_PROCESSING_MODE_SINK_SOURCE(mod)) {
477489
comp_err(dev, "no sink present on period size calculation");
478490
return -EINVAL;
479491
}
480492

481-
mod->period_bytes = audio_stream_period_bytes(&sink->stream, dev->frames);
493+
/* A sinkless module still needs at least one source. */
494+
if (!sink && !comp_dev_get_first_data_producer(dev)) {
495+
comp_err(dev, "no source or sink buffer connected");
496+
return -EINVAL;
497+
}
498+
499+
mod->period_bytes = sink ? audio_stream_period_bytes(&sink->stream, dev->frames) : 0;
482500
comp_dbg(dev, "got period_bytes = %u", mod->period_bytes);
483501

484502
/* no more to do for sink/source mode */

0 commit comments

Comments
 (0)