Skip to content

services/speaker: keep PCM playback fed under app load - #2039

Open
ShinkoNet wants to merge 3 commits into
coredevices:mainfrom
ShinkoNet:audio/pcm-playback-reliability
Open

ShinkoNet wants to merge 3 commits into
coredevices:mainfrom
ShinkoNet:audio/pcm-playback-reliability

Conversation

@ShinkoNet

@ShinkoNet ShinkoNet commented Sep 8, 2026

Copy link
Copy Markdown

CPU-heavy apps can leave speaker PCM refills late. The driver already dispatches its callback on KernelBG, but the service queues another callback, refills only one block after a delay, and leaves KernelBG below app priority. The SF32LB circular buffer also publishes its length before copying bytes while the DMA interrupt consumes the same buffer.

  • Serialize SF32LB circular-buffer writes against the DMA interrupt.
  • Refill directly from the driver callback and use the reported free capacity to catch up.
  • Hold raised KernelBG priority during playback, with balanced reference counting for priority requests.

Tested on Pebble Time 2, and also confirmed QEMU still output audio.

I've been working on a Game Boy Color emulator, and it creates a lot of CPU usage. These audio fixes were tested in my own fork along with my emulator (Pebbleboy) to confirm the audio no longer stuttered during emulation.

Ray Bellett added 3 commits September 8, 2026 13:24
Protect circular-buffer writes from the DMA consumer so it cannot observe a partially
copied block or race the buffer bookkeeping.

Signed-off-by: Ray Bellett <shinko@netcavy.net>
The audio drivers already deliver refill callbacks on KernelBG. Avoid queuing another
callback and refill the reported free capacity after a delayed stream callback.

Signed-off-by: Ray Bellett <shinko@netcavy.net>
Hold a raised KernelBG priority while audio is active. Reference-count priority requests
so stopping playback cannot release another user's request.

Signed-off-by: Ray Bellett <shinko@netcavy.net>
@ShinkoNet ShinkoNet closed this Sep 8, 2026
@ShinkoNet ShinkoNet reopened this Sep 8, 2026
@ShinkoNet
ShinkoNet marked this pull request as ready for review September 8, 2026 03:35
@ShinkoNet

Copy link
Copy Markdown
Author

https://github.com/ShinkoNet/pebbleboy
Here's my app that is currently using these changes (along with a seperate filesystem blob API I've yet to make a PR for) as an example.

prv_update_volume_analytics(effective_vol);

// Keep DMA refills ahead of CPU-heavy app work until playback stops.
system_task_enable_raised_priority(true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This boosts all KernelBG callbacks above the app for the entire playback lifetime, including long-lived streams. Can the priority boost be scoped to pending refill work instead, so unrelated background callbacks do not also preempt the app?

static void prv_audio_trans_cb(uint32_t *free_size) {
// Schedule actual refill work on system task to keep ISR-context callback short
system_task_add_callback(prv_refill_bg, NULL);
// The drivers already dispatch on KernelBG; refill here and catch up missed blocks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This assumes free_size is the amount currently writable, but the QEMU driver always passes a hard-coded full-buffer size (4096 * sizeof(int16_t)) on every interrupt. Would need to be changed in the QEMU driver

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.

2 participants