Double-buffer RawSample (single_buffer=False) played with loop=False hangs; playing never clears

Offen
#11,086 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Anfängerfreundlichkeit
25/100
Issue-Typ
Bug
Klarheit
Muss geklärt werden
Aktivitätsstatus
Ruhig
Tech-Stack
c
Bereich
embedded-iot

Rechercherichtung

Start by reading the RawSample documentation and shared-module/audiocore/RawSample.c, then trace the rp2 behavior in ports/raspberrypi/audio_dma.c. Reproduce the hang and check the listed audio ports. Done means the intended double-buffer plus loop=False semantics are decided and implemented, with behavior verified across ports.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

audio bug

Note: This issue was written by Claude (via Claude Code), not by a human. It was filed at the request of @dhalbert while working on the fixes for #10539 (PR #11085).

@dhalbert says: This is kind of an edge case; no one has reported it as a bug; I discovered it while testing audio PR's.

Summary

A RawSample constructed with single_buffer=False and played with loop=False plays a short burst and then hangs: audio stops, but .playing never becomes False. Observed on raspberrypi; likely affects other ports (needs verification — see below).

sample = audiocore.RawSample(sine_wave, sample_rate=8000, single_buffer=False)
i2s.play(sample, loop=False)
while i2s.playing:   # never exits
    pass

Root cause (raspberrypi)

A double-buffer RawSample's get_buffer (shared-module/audiocore/RawSample.c) returns half the buffer with GET_BUFFER_DONE and alternates halves forever — it never signals true end-of-data.

On rp2 (ports/raspberrypi/audio_dma.c), audio_dma_load_next_block treats GET_BUFFER_DONE && !loop by pointing the DMA channel's chain at itself to stop. With both channels chained to themselves, the ping-pong breaks: channel[0] plays its half and stops, and dma_callback_fun never re-triggers (channels_to_load_mask == 0, filled_count == 1). Audio halts after one half, and playing_in_progress is never cleared. The proper end-of-sample detection (output_length_used == 0) never fires because RawSample always returns nonzero halves.

WaveFile in double-buffer mode is unaffected: it returns GET_BUFFER_MORE_DATA for intermediate reads and a truly-empty GET_BUFFER_DONE at EOF, so playback terminates cleanly.

Why this is tricky (semantics)

Per the RawSample docstring, single_buffer=False (double-buffered) is intended for continuous, live-update playback — updating the buffer while it plays — and its examples all use loop=True. single_buffer=False + loop=False on a static buffer is effectively ill-defined: the sample has no natural end, so "play once and stop" has no clear meaning.

A fix probably needs a decision at the RawSample/shared layer about what this combination should do (e.g. play the whole buffer through once then stop, treat it as looping, or reject the combination), rather than a per-port patch.

TODO

  • Reproduce on other audio ports (espressif, nordic, atmel-samd, mimxrt10xx, stm, zephyr-cp) and note behavior per port.
  • Decide the intended semantics for double-buffer + loop=False.
  • Implement, likely at the RawSample/shared-module layer.

Context

Discovered while fixing the single-buffer loop=False "no sound" / stuck-playing bugs in #10539 (PR #11085). This double-buffer case was deliberately scoped out of that PR.

Vorherrschende Sprache
C
Sterne
4.6k
Forks
1.4k
Ø Merge
1 T. 8 Std.
Gemergte PRs (30 T.)
183

Entwicklungsumgebung

Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus adafruit/circuitpython

Alle Issues in adafruit/circuitpython

Ähnliche Issues

Weitere Issues zu C

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.