Skip to content

Flush the final partial speaker buffer - #325

Merged
lovyan03 merged 2 commits into
m5stack:developfrom
ainyan03:spk_tail_flush
Aug 18, 2026
Merged

Flush the final partial speaker buffer#325
lovyan03 merged 2 commits into
m5stack:developfrom
ainyan03:spk_tail_flush

Conversation

@ainyan03

Copy link
Copy Markdown
Contributor

Problem

When a wav reaches its natural end partway through the speaker task's working
buffer and no follow-up request has been published, the channel loop exits
through an early continue before the samples already mixed into the working
buffer are counted into data_length. Everything generated in that final
round — up to one working buffer — is silently dropped instead of being sent
to I2S.

For a single playRaw() call this cuts off the tail of the sound. An
application that streams audio as consecutive short playRaw() chunks can
lose the tail of every chunk whenever publishing the next request loses the
race against the speaker task, which turns into periodic gaps.

Fix

The task now tracks whether it reached the exit path through natural
exhaustion of the request. In that case the number of samples generated so
far is promoted into data_length (with max semantics, so other channels
mixed into the same buffer are unaffected) before the loop moves on, and the
partial buffer is transmitted as usual.

Explicit stop requests (stop() markers) keep the existing behavior of
discarding immediately: cutting the sound short is the point of a stop, so
nothing is flushed on that path.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an audio playback edge case in Speaker_Class::spk_task where the final, partially-filled mix buffer could be dropped when a WAV ends naturally mid-buffer and no subsequent request is published in time, causing audible cutoffs/gaps.

Changes:

  • Track whether a channel ended via natural exhaustion and should flush a partial buffer (flush_partial).
  • Promote the amount of already-mixed audio into data_length on the early-continue path so the partial buffer is still transmitted.
  • Preserve the existing “discard immediately” behavior for explicit stop-marker requests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/utility/Speaker_Class.cpp Outdated
{ // nothing to do; a writer caught mid-publish raises the bit itself.
ch_info->diff = 0;
ch_info->index = 0;
if (flush_partial && data_length < idx) { data_length = idx; }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An out-of-bounds read cannot actually occur here: dma_buf_len is rounded down to an even value when the task starts, and sound_buf32 is zeroed with memset at the top of every round, so with an odd data_length the packing loop's final v2 reads an in-bounds, zero-initialized element.

That said, an odd count did become newly reachable through this flush path, and it leaves a trailing half-word in the transmitted bytes (on the HW v1 layout that replaces the final real sample with the zero half). Rounding the flushed count up to even avoids both concerns at the cost of one silent padding sample, so I adopted that in 94dffd8.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@lovyan03
lovyan03 merged commit b20c4f7 into m5stack:develop Aug 18, 2026
27 checks passed
@ainyan03
ainyan03 deleted the spk_tail_flush branch August 18, 2026 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants