You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Giga: Bluetooth LE traffic starves audio playback #291
On the Arduino GIGA R1 WiFi (DISPLAY_SHIELD variant), a Bluetooth LE session while midiEngine plays a MIDI file more than doubles the audio the DAC misses. Bluetooth itself keeps working: a BLE HID host session against a keyboard on another board received 99 of 99 events with the right text while the file played.
Measured with midiEngine playing a General MIDI file through the GeneralUser GS SoundFont at 48 kHz stereo, reading _audioif.dac_stats() before and after a 37-second stretch, and sampling the DAC's output register at 2 kHz in 100 ms windows:
Over 37 s
Frames played
Starved frames
Silent 100 ms windows
No Bluetooth
1,787,102
128,603 (7.2%)
12 of 372
BLE HID host session (aioble)
1,811,024
311,404 (17.2%)
42 of 367
Both runs were at the REPL with the launcher's timers running, not under appkit.serve(), and the 2 kHz sampling timer costs some CPU of its own, so the absolute figures are higher than an app would see. The difference between the two rows is the Bluetooth stack's time on the same core as the audio render.
The render moving to the DAC interrupt (#290) should cover this along with garbage collections; this issue is the measurement that Bluetooth is a second source of the same starvation.
The Bluetooth stack on its own doesn't starve the audio. To separate it from the Python side, I played synthio at 48 kHz on the same board and read _audioif.dac_stats() around each run:
So even with the render close to saturating the core, the controller and host stack leave it alone. What differs in the midiEngine run above is aioble: its IRQ handler and the asyncio tasks around it run as Python in scheduler context, between render calls, and that's where the extra 10% of starved frames most likely comes from. That is the same mechanism as the garbage collections, so the render moving to the DAC interrupt (#290) is still the fix for both.
Not rechecked: the midiEngine run itself, because its USB stick wasn't detected this time.
Re-run with #392 and audiodsp's interrupt hooks on a GIGA R1 with the Display Shield. A PC central wrote to the board about 50 times a second while the board notified every 10 ms, for 60 s, with Synth Station's electric piano playing a chord that changed every second:
Firmware
Starved frames
Of played
Writes received
Notifies sent
Interpreter render (before)
1,721
2,880,338
2,893
5,435
Interrupt render
0
2,880,549
3,116
5,494
The Bluetooth traffic got through the same in both runs; only the audio changed.
Fixed by #392: the GIGA renders from the DAC interrupt now, so aioble's Python callbacks can't hold the render off. In the BLE HID host case above, starved frames went from 1,721 to 0 (#290 has the full figures).
Activity
bdbarnett commentedon Nov 10, 2026
The Bluetooth stack on its own doesn't starve the audio. To separate it from the Python side, I played synthio at 48 kHz on the same board and read
_audioif.dac_stats()around each run:So even with the render close to saturating the core, the controller and host stack leave it alone. What differs in the midiEngine run above is aioble: its IRQ handler and the asyncio tasks around it run as Python in scheduler context, between render calls, and that's where the extra 10% of starved frames most likely comes from. That is the same mechanism as the garbage collections, so the render moving to the DAC interrupt (#290) is still the fix for both.
Not rechecked: the midiEngine run itself, because its USB stick wasn't detected this time.
bdbarnett commentedon Nov 10, 2026
Re-run with #392 and audiodsp's interrupt hooks on a GIGA R1 with the Display Shield. A PC central wrote to the board about 50 times a second while the board notified every 10 ms, for 60 s, with Synth Station's electric piano playing a chord that changed every second:
The Bluetooth traffic got through the same in both runs; only the audio changed.
bdbarnett commentedon Nov 10, 2026
Fixed by #392: the GIGA renders from the DAC interrupt now, so aioble's Python callbacks can't hold the render off. In the BLE HID host case above, starved frames went from 1,721 to 0 (#290 has the full figures).