diff --git a/src/audio/volume/volume.c b/src/audio/volume/volume.c index aed356a3ec83..4a4ab881ce8e 100644 --- a/src/audio/volume/volume.c +++ b/src/audio/volume/volume.c @@ -556,6 +556,7 @@ static int volume_process(struct processing_module *mod, struct output_stream_buffer *output_buffers, int num_output_buffers) { struct vol_data *cd = module_get_private_data(mod); + struct audio_stream *source = input_buffers[0].data; uint32_t avail_frames = input_buffers[0].size; uint32_t frames; int64_t prev_sum = 0; @@ -571,12 +572,23 @@ static int volume_process(struct processing_module *mod, frames = avail_frames; } else if (cd->ramp_type == SOF_VOLUME_LINEAR_ZC) { /* with ZC ramping look for next ZC offset */ - frames = cd->zc_get(input_buffers[0].data, cd->vol_ramp_frames, &prev_sum); + frames = cd->zc_get(source, cd->vol_ramp_frames, &prev_sum); + /* Align frames count to audio stream constraints */ + frames = audio_stream_align_frames_round_up(source, frames); } else { - /* without ZC process max ramp chunk */ - frames = cd->vol_ramp_frames; + /* During volume ramp align the number of frames used in this + * gain step. Align up since with low rates this would typically + * become zero. + */ + frames = audio_stream_align_frames_round_up(source, cd->vol_ramp_frames); } + /* Cancel the gain step for ZC or smaller ramp step if it exceeds + * the available frames. + */ + if (frames > avail_frames) + frames = avail_frames; + if (!cd->ramp_finished) { volume_ramp(mod); cd->vol_ramp_elapsed_frames += frames; diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index 9703ec9cadea..e6ed374f404f 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -612,6 +612,38 @@ audio_stream_avail_frames_aligned(const struct audio_stream *source, return MIN(src_frames, sink_frames); } +/** + * Rounds down a frame count to meet the alignment constraint of the stream. + * @param stream Audio stream with alignment requirements set. + * @param frames Frame count to round down. + * @return Largest aligned frame count less than or equal to frames. + */ +static inline uint32_t audio_stream_align_frames_round_down(const struct audio_stream *stream, + uint32_t frames) +{ + uint16_t align = stream->runtime_stream_params.align_frame_cnt; + + return (frames / align) * align; +} + +/** + * Rounds up a frame count to meet the alignment constraint of the stream. + * @param stream Audio stream with alignment requirements set. + * @param frames Frame count to round up. + * @return Smallest aligned frame count greater than or equal to frames. + */ +static inline uint32_t audio_stream_align_frames_round_up(const struct audio_stream *stream, + uint32_t frames) +{ + uint16_t align = stream->runtime_stream_params.align_frame_cnt; + uint32_t aligned_frames = (frames / align) * align; + + if (aligned_frames < frames) + aligned_frames += align; + + return aligned_frames; +} + /** * Updates the buffer state after writing to the buffer. * @param buffer Buffer to update.