From 1ffe199b5111a45ad411ad20f069661c48878f07 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 4 Dec 2023 13:21:53 -0800 Subject: [PATCH] google_rtc_audio_processing: Handle inactive reference input Close the loop on "optional pipeline" state management. When the component connected to the reference input is inactive, synthesize zeros in the buffer being fed to echo cancellation processing. Now the capture pipe is no longer necessary and no host DMA needs to be happening on the playback channel just to feed AEC. You can start and stop playback at any time and the stream will accommodate. Note that mic startup happens on the host's schedule and isn't synchronous, so there's a case when exercising this code where the reference stream can be a few 10ms blocks ahead of the mic when it finally arrives. Add a "catch up" check to discard stale samples. Signed-off-by: Andy Ross --- .../google/google_rtc_audio_processing.c | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/audio/google/google_rtc_audio_processing.c b/src/audio/google/google_rtc_audio_processing.c index 8297800afa48..cefb0271141e 100644 --- a/src/audio/google/google_rtc_audio_processing.c +++ b/src/audio/google/google_rtc_audio_processing.c @@ -713,23 +713,45 @@ static int google_rtc_audio_processing_process(struct processing_module *mod, struct audio_stream *ref = input_buffers[cd->aec_reference_source].data; struct audio_stream *out = output_buffers[0].data; + struct comp_buffer *refbuf = container_of(ref, struct comp_buffer, stream); + bool ref_ok = refbuf->source->state == COMP_STATE_ACTIVE; + + /* Would be cleaner to store a bit of state to elide a bzero + * we already did, but we'd be doing the copy of real data in + * the ref_ok state anyway. + */ + if (!ref_ok) + bzero(cd->aec_reference_buffer, + (cd->num_frames * cd->num_aec_reference_channels + * sizeof(cd->aec_reference_buffer[0]))); + int micchan = audio_stream_get_channels(mic); int refchan = audio_stream_get_channels(ref); int fmic = audio_stream_get_avail_frames(mic); int fref = audio_stream_get_avail_frames(ref); - int frames = MIN(fmic, fref); + int frames = ref_ok ? MIN(fmic, fref) : fmic; int n, frames_rem; + /* If fref > fmic (common at pipeline startup if + * playback was already active), we should consume the early + * samples so AEC compares the most recent values. + */ + if (ref_ok && fref > fmic) + audio_stream_consume(ref, (fref - fmic) * audio_stream_frame_bytes(ref)); + for (frames_rem = frames; frames_rem; frames_rem -= n) { n = MIN(frames, cd->num_frames - cd->raw_mic_buffer_frame_index); audio_stream_copy_to_linear(mic, 0, cd->raw_mic_buffer, cd->raw_mic_buffer_frame_index, n * micchan); - audio_stream_copy_to_linear(ref, 0, cd->aec_reference_buffer, - cd->aec_reference_frame_index, - n * refchan); + + if (ref_ok) + audio_stream_copy_to_linear(ref, 0, cd->aec_reference_buffer, + cd->aec_reference_frame_index, + n * refchan); + cd->raw_mic_buffer_frame_index += n; if (cd->raw_mic_buffer_frame_index >= cd->num_frames) {