Skip to content

Commit 201de56

Browse files
committed
audio: webrtc_aec: dynamically resolve ref source and drop excess frames
Re-resolve mic and playback-reference sources in webrtc_aec_process() and webrtc_aec_is_ready_to_process() because IPC4 playback pipelines may bind or unbind dynamically while capture is active, and drop excess reference frames so playback backpressure does not stall capture or overflow the reference ring buffer. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 368b5e8 commit 201de56

1 file changed

Lines changed: 113 additions & 32 deletions

File tree

‎src/audio/webrtc_aec/webrtc_aec.c‎

Lines changed: 113 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,67 @@ static void s16_to_sink(struct sof_sink *dst, int16_t src[][WEBRTC_AEC_FIFO_FRAM
168168
sink_commit_buffer(dst, nbytes);
169169
}
170170

171+
static void src_drop_frames(struct sof_source *src, int frames)
172+
{
173+
size_t frame_bytes = source_get_frame_bytes(src);
174+
const void *data_ptr, *buf_start;
175+
size_t buf_size, nbytes;
176+
177+
if (frames <= 0 || !frame_bytes)
178+
return;
179+
180+
nbytes = (size_t)frames * frame_bytes;
181+
if (!source_get_data(src, nbytes, &data_ptr, &buf_start, &buf_size))
182+
source_release_data(src, nbytes);
183+
}
184+
185+
static void webrtc_aec_resolve_sources(struct sof_source **sources, int num_of_sources,
186+
struct sof_sink **sinks, int num_of_sinks,
187+
int *mic_idx, int *ref_idx)
188+
{
189+
*mic_idx = 0;
190+
*ref_idx = -1;
191+
192+
if (num_of_sources <= 1)
193+
return;
194+
195+
#ifdef CONFIG_IPC_MAJOR_4
196+
{
197+
uint32_t q0 = IPC4_SINK_QUEUE_ID(source_get_id(sources[0]));
198+
uint32_t q1 = IPC4_SINK_QUEUE_ID(source_get_id(sources[1]));
199+
200+
if (q0 != q1) {
201+
if (q0 == 0) {
202+
*mic_idx = 0;
203+
*ref_idx = 1;
204+
} else {
205+
*mic_idx = 1;
206+
*ref_idx = 0;
207+
}
208+
return;
209+
}
210+
}
211+
#endif
212+
213+
if (num_of_sinks > 0) {
214+
if (source_get_pipeline_id(sources[0]) == sink_get_pipeline_id(sinks[0]) &&
215+
source_get_pipeline_id(sources[1]) != sink_get_pipeline_id(sinks[0])) {
216+
*mic_idx = 0;
217+
*ref_idx = 1;
218+
return;
219+
}
220+
if (source_get_pipeline_id(sources[1]) == sink_get_pipeline_id(sinks[0]) &&
221+
source_get_pipeline_id(sources[0]) != sink_get_pipeline_id(sinks[0])) {
222+
*mic_idx = 1;
223+
*ref_idx = 0;
224+
return;
225+
}
226+
}
227+
228+
*mic_idx = 0;
229+
*ref_idx = 1;
230+
}
231+
171232
/* ----------------------------------------------------------------
172233
* module_interface operations
173234
* ---------------------------------------------------------------- */
@@ -226,21 +287,8 @@ __cold static int webrtc_aec_prepare(struct processing_module *mod,
226287
return -EINVAL;
227288
}
228289

229-
if (num_of_sources == 1) {
230-
cd->mic_src = 0;
231-
cd->ref_src = -1;
232-
} else if (source_get_pipeline_id(sources[0]) == sink_get_pipeline_id(sinks[0]) &&
233-
source_get_pipeline_id(sources[1]) != sink_get_pipeline_id(sinks[0])) {
234-
cd->mic_src = 0;
235-
cd->ref_src = 1;
236-
} else if (source_get_pipeline_id(sources[1]) == sink_get_pipeline_id(sinks[0]) &&
237-
source_get_pipeline_id(sources[0]) != sink_get_pipeline_id(sinks[0])) {
238-
cd->mic_src = 1;
239-
cd->ref_src = 0;
240-
} else {
241-
cd->mic_src = 0;
242-
cd->ref_src = 1;
243-
}
290+
webrtc_aec_resolve_sources(sources, num_of_sources, sinks, num_of_sinks,
291+
&cd->mic_src, &cd->ref_src);
244292

245293
mic_fmt = source_get_frm_fmt(sources[cd->mic_src]);
246294
mic_rate = source_get_rate(sources[cd->mic_src]);
@@ -344,29 +392,52 @@ static int webrtc_aec_process(struct processing_module *mod,
344392
struct sof_sink **sinks, int num_of_sinks)
345393
{
346394
struct webrtc_aec_comp_data *cd = module_get_private_data(mod);
347-
struct sof_source *mic = sources[cd->mic_src];
348-
struct sof_source *ref = cd->ref_src >= 0 ? sources[cd->ref_src] : NULL;
349-
struct sof_sink *out = sinks[0];
350-
int fmic = (int)source_get_data_frames_available(mic);
351-
int fref = ref ? (int)source_get_data_frames_available(ref) : 0;
352-
int n, drain, c;
353-
354-
if (fmic <= 0)
395+
struct sof_source *mic;
396+
struct sof_source *ref;
397+
struct sof_sink *out;
398+
int mic_idx, ref_idx;
399+
int fmic, fref, n, drain, c;
400+
bool ref_s32;
401+
402+
if (num_of_sources < 1 || num_of_sinks < 1)
355403
return 0;
356404

357-
/* Cap to available space in input accumulation buffers */
405+
webrtc_aec_resolve_sources(sources, num_of_sources, sinks, num_of_sinks,
406+
&mic_idx, &ref_idx);
407+
cd->mic_src = mic_idx;
408+
cd->ref_src = ref_idx;
409+
410+
mic = sources[mic_idx];
411+
ref = ref_idx >= 0 ? sources[ref_idx] : NULL;
412+
out = sinks[0];
413+
fmic = (int)source_get_data_frames_available(mic);
414+
fref = ref ? (int)source_get_data_frames_available(ref) : 0;
415+
416+
/* Cap to available space in input accumulation and output sink buffers */
358417
n = MIN(fmic, WEBRTC_AEC_FIFO_FRAMES - cd->buffered_in_frames);
359-
if (n <= 0)
418+
n = MIN(n, (int)sink_get_free_frames(out));
419+
if (n <= 0) {
420+
if (ref && fref > 0) {
421+
size_t fb = source_get_frame_bytes(ref);
422+
int keep = fb ? (int)(source_get_min_available(ref) / fb) : 0;
423+
424+
if (fref > keep)
425+
src_drop_frames(ref, fref - keep);
426+
}
360427
return 0;
428+
}
361429

362430
/* Convert mic input to per-channel S16 */
363431
src_to_s16(mic, n, cd->mic_buf, cd->buffered_in_frames, cd->channels, cd->is_s32);
364432

365433
/* Convert ref input to per-channel S16; if starved/silent, fill with silence */
434+
ref_s32 = ref ? (source_get_frm_fmt(ref) == SOF_IPC_FRAME_S32_LE) : cd->is_s32;
366435
if (fref >= n) {
367-
src_to_s16(ref, n, cd->ref_buf, cd->buffered_in_frames, cd->channels, cd->is_s32);
436+
if (fref > n)
437+
src_drop_frames(ref, fref - n);
438+
src_to_s16(ref, n, cd->ref_buf, cd->buffered_in_frames, cd->channels, ref_s32);
368439
} else if (fref > 0) {
369-
src_to_s16(ref, fref, cd->ref_buf, cd->buffered_in_frames, cd->channels, cd->is_s32);
440+
src_to_s16(ref, fref, cd->ref_buf, cd->buffered_in_frames, cd->channels, ref_s32);
370441
for (c = 0; c < cd->channels; c++)
371442
memset(&cd->ref_buf[c][cd->buffered_in_frames + fref], 0,
372443
(size_t)(n - fref) * sizeof(int16_t));
@@ -649,17 +720,27 @@ static bool webrtc_aec_is_ready_to_process(struct processing_module *mod,
649720
int num_of_sinks)
650721
{
651722
struct webrtc_aec_comp_data *cd = module_get_private_data(mod);
652-
struct sof_source *mic;
723+
struct sof_source *mic, *ref;
653724
struct sof_sink *out;
725+
int mic_idx, ref_idx;
654726

655-
if (!cd || !cd->configured || num_of_sources <= cd->mic_src || num_of_sinks < 1)
727+
if (!cd || !cd->configured || num_of_sources < 1 || num_of_sinks < 1)
656728
return false;
657729

658-
mic = sources[cd->mic_src];
730+
webrtc_aec_resolve_sources(sources, num_of_sources, sinks, num_of_sinks,
731+
&mic_idx, &ref_idx);
732+
mic = sources[mic_idx];
733+
ref = ref_idx >= 0 ? sources[ref_idx] : NULL;
659734
out = sinks[0];
660735

661-
return source_get_data_available(mic) >= source_get_min_available(mic) &&
662-
sink_get_free_size(out) >= sink_get_min_free_space(out);
736+
if (source_get_data_available(mic) >= source_get_min_available(mic) &&
737+
sink_get_free_size(out) >= sink_get_min_free_space(out))
738+
return true;
739+
740+
if (ref && source_get_data_available(ref) >= 2 * source_get_min_available(ref))
741+
return true;
742+
743+
return false;
663744
}
664745

665746
static const struct module_interface webrtc_aec_interface = {

0 commit comments

Comments
 (0)