From 263a6d0fe0e3ea100b3c308f621354781d577cdc Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 15 Mar 2022 19:42:38 +0200 Subject: [PATCH] mixer: add logic to maintain data flow when sources are paused In a topology where mixer is connected to multiple source pipelines, the mixer<->DAI downstream pipeline for playback is kept running when sources are put to PAUSED state. This design means that mixer_copy() needs to continue to produce output samples as the DAI is kept running as well. There is existing code to generate silence when all sources are PAUSED. A problem remains in the sequence when sources are RELEASED. On the first iteration after RELEASE, the source state can be changed (so mixer sees non-zero num_mix_sources). But the sources may not have any data available on the first cycle. This can lead to XRUNs observed at the DAI as the mixer is not continuously producing data in ACTIVE state. Address this issue by adding a "sources_inactive" state to mixer. When all sources are inactive, mixer enters this state. When sources are resumed, mixer will note this state, and continue to generate silence (on its output) until at least one source starts generating audio data. This ensures continuous audio output to the mixer downstream pipeline. The change is not sufficient on its own, but is part of the fixes to address: https://github.com/thesofproject/sof/issues/5469 Signed-off-by: Kai Vehmanen --- src/audio/mixer.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/audio/mixer.c b/src/audio/mixer.c index a9ee6e584f5b..ca7a446285b4 100644 --- a/src/audio/mixer.c +++ b/src/audio/mixer.c @@ -55,6 +55,8 @@ struct mixer_data { struct ipc4_base_module_cfg base_cfg; #endif + bool sources_inactive; + void (*mix_func)(struct comp_dev *dev, struct audio_stream *sink, const struct audio_stream **sources, uint32_t count, uint32_t frames); @@ -343,23 +345,6 @@ static int mixer_copy(struct comp_dev *dev) return 0; } - /* write zeros if all sources are inactive */ - if (num_mix_sources == 0) { - uint32_t free_frames; - sink = buffer_acquire(sink); - free_frames = audio_stream_get_free_frames(&sink->stream); - frames = MIN(frames, free_frames); - sink_bytes = frames * audio_stream_frame_bytes(&sink->stream); - sink = buffer_release(sink); - - if (!audio_stream_set_zero(&sink->stream, sink_bytes)) { - buffer_stream_writeback(sink, sink_bytes); - comp_update_buffer_produce(sink, sink_bytes); - } - - return 0; - } - sink = buffer_acquire(sink); /* check for underruns */ @@ -372,6 +357,31 @@ static int mixer_copy(struct comp_dev *dev) sources[i] = buffer_release(sources[i]); } + if (!num_mix_sources || (frames == 0 && md->sources_inactive)) { + /* + * Generate silence when sources are inactive. When + * sources change to active, additionally keep + * generating silence until at least one of the + * sources start to have data available (frames!=0). + */ + frames = audio_stream_get_free_frames(&sink->stream); + sink_bytes = frames * audio_stream_frame_bytes(&sink->stream); + sink = buffer_release(sink); + if (!audio_stream_set_zero(&sink->stream, sink_bytes)) { + buffer_stream_writeback(sink, sink_bytes); + comp_update_buffer_produce(sink, sink_bytes); + } + + md->sources_inactive = true; + + return 0; + } + + if (md->sources_inactive) { + md->sources_inactive = false; + comp_dbg(dev, "mixer_copy exit sources_inactive state"); + } + sink = buffer_release(sink); /* Every source has the same format, so calculate bytes based