Skip to content

fix(example): wait for the mic fill before returning samples - #20

Open
ACEFGI wants to merge 1 commit into
mainfrom
fix/m5mic-example-async-record
Open

fix(example): wait for the mic fill before returning samples#20
ACEFGI wants to merge 1 commit into
mainfrom
fix/m5mic-example-async-record

Conversation

@ACEFGI

@ACEFGI ACEFGI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

M5MicDriver::read() returned maxSamples the instant M5.Mic.record() returned. record() is asynchronous — it queues the destination buffer and returns while M5Unified's mic task fills it in the background — so every read handed back a buffer that had not been written yet.

The destination was also the caller's buffer, so the mic task kept writing into memory the caller already considered its own, for as long as the fill took.

Fix

Record into a buffer the driver owns, and copy out only once the fill has completed.

The completion poll needs a tick before it starts: Mic_Class::isRecording() is gated on _is_recording, a flag the mic task sets itself once it has dequeued work. Between record() queueing a request and the task starting it, isRecording() reads 0 with the fill still pending, so an immediate while (isRecording()) falls straight through and copies an unfilled buffer.

Notes

This keeps the example simple — one request in flight, waited to completion — which is correct but does leave the mic task's queue empty between reads. A driver doing continuous capture wants the queue kept non-empty instead, since M5Unified's mic task silently discards the partially consumed DMA chunk it is holding whenever it parks. The Hawthorn firmware's production M5Microphone does that with a three-buffer rotation over M5Unified's two-request lag.

Found while reviewing the same defect in that production driver.

🤖 Generated with Claude Code

M5.Mic.record() is asynchronous: it queues the destination buffer and
returns while M5Unified's mic task fills it in the background. M5MicDriver
returned maxSamples immediately, so every read handed back a buffer the
task had not written yet.

Worse, the destination was the *caller's* buffer, which the mic task went
on writing after read() returned — a write into memory the caller already
considered its own.

Record into a buffer the driver owns and copy out once the fill completes.
The completion poll needs a tick first: isRecording() is gated on a flag
the mic task sets itself, so it reads 0 until the task dequeues the
request and the wait would otherwise fall straight through.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant