Hello Nordic Support Team,
I'm developing a BLE audio/walkie-talkie application on an nRF54L15 DK using Zephyr, communicating with an Android smartphone. I'm seeing a significant and irregular delay when receiving data on the nRF side over an L2CAP Credit-Based Connection-Oriented Channel (CoC), and would appreciate your input.
ISSUE
The Android app sends audio packets at a steady ~20 ms interval. On the nRF54L15 side, however, packets arrive irregularly, with gaps of roughly 100-200 ms (occasionally more). Example RX log:
BLE RX #1: SEQ=1 packet=164 payload=160 interval=0 ms
BLE RX #2: SEQ=2 packet=164 payload=160 interval=101 ms
BLE RX #3: SEQ=3 packet=164 payload=160 interval=149 ms
BLE RX #4: SEQ=5 packet=164 payload=160 interval=117 ms
BLE RX #5: SEQ=6 packet=164 payload=160 interval=109 ms
BLE RX #6: SEQ=7 packet=164 payload=160 interval=110 ms
BLE RX #7: SEQ=8 packet=164 payload=160 interval=101 ms
BLE RX #8: SEQ=9 packet=164 payload=160 interval=125 ms
BLE RX #9: SEQ=10 packet=164 payload=160 interval=180 ms
As a sanity check, I also tested audio data sent from one Android phone to another Android phone (Android -> Android, i.e. not involving the nRF54L15 at all) over BLE, and in that case I am able to receive audio data every 20 ms without any delay. This suggests the Android side is capable of sending and receiving at a consistent 20 ms interval, which points to the issue being specific to reception on the nRF54L15 side rather than an Android-side sending irregularity.
Expected vs. actual timing:
Expected (Android send / nRF receive both at ~20 ms):
Packet 1 -> 0 ms, Packet 2 -> ~20 ms, Packet 3 -> ~40 ms, Packet 4 -> ~60 ms, Packet 5 -> ~80 ms
Actual nRF reception:
Packet 1 -> 0 ms, Packet 2 -> ~100 ms, Packet 3 -> ~150 ms, Packet 4 -> ~117 ms, Packet 5 -> ~109 ms, Packet 6 -> ~110 ms
This irregularity makes reliable real-time audio streaming impossible.
CONNECTION PARAMETERS
Connection interval: 10 (12.50 ms)
Latency: 0
Supervision timeout: 1000 ms
L2CAP CONFIGURATION
Channel connects successfully:
L2CAP channel connected, PSM=0x0086
RX: CID=0x0040 MTU=245 MPS=247 credits=1
TX: CID=0x004f MTU=65535 MPS=272 credits=0
Android sends ~164-byte application packets (2 bytes sequence number + 2 bytes payload length + 160 bytes audio payload), which fits within the nRF L2CAP MPS of 247 bytes.
ZEPHYR L2CAP RX TIMING INVESTIGATION
I instrumented the Zephyr L2CAP receive path:
bt_l2cap_recv() -> L2CAP RX work processing -> l2cap_chan_le_recv() -> application recv callback (l2cap_recv())
For every packet, the time from bt_l2cap_recv() to my application callback is only a few microseconds, e.g.:
T2: bt_l2cap_recv t=9445 len=166
T3: CID=0x0040 len=166
T4: L2CAP packet queued t=9445
T5: L2CAP RX work processing t=9445
T6: l2cap_chan_le_recv len=166 credits=0
T7: APPLICATION RX len=+
This confirms the 100-200 ms delay is not introduced by Zephyr's host-side L2CAP processing or my application callback - the packets are already arriving at the host irregularly.
I'm happy to share the complete L2CAP channel implementation, prj.conf, Android L2CAP implementation, and additional logs if that would help.
Thank you for your support.