We make a BLE peripheral that streams continuously. It's been running against Android, Windows, macOS and iOS for years. Android and Windows sit at ~1000 kbps and stay there — many host devices, many OS versions, no per-host tuning. macOS and iOS give us about half that. We've sniffed the BLE link using a Bluetooth sniffer to find out where it goes.
Same board, same firmware, every session. Read off the air trace, not from host APIs:
2M PHY both directions (LL_PHY_UPDATE_IND 0x02 / 0x02)
DLE max_tx_octets = 251
ATT MTU 247
15.00 ms interval, peripheral latency 0
no encryption
no other BLE or BT Classic connections active during the session (all other devices removed and forgotten)
WiFi turned off for around half of the sessions, didn't seem to make any difference
Peripheral airtime per connection event:
central
airtime/event
duty @ 15 ms
throughput
Android
11.14 ms
74%
995 kbps, sustained
Windows
≥10.70 ms
≥71%
~1000 kbps, sustained
macOS
6.96 ms
46%
561 kbps
iOS
6.96 ms typical
46%
~560–600 kbps
macOS comes out median 6.96, p90 6.96, max 7.09 across a whole session. Same number every time. iOS normally sits in the same place, with occasional brief excursions up to Android-like performance before dropping back down.
Those excursions are worth describing, because they're the interesting part. In a handful of sessions out of many, iOS runs at 12.53 ms, 84% duty, ~1030 kbps. It never holds. It drops back inside 150 ms, with no renegotiation, no parameter change and no channel-map change anywhere in the trace. Sometimes it parks at 8.35 ms for ten seconds before moving again. This isn't us saying iOS is fine in practice — it clearly isn't, we can't ship against it. The point is that the radio and the stack demonstrably can fill a 12.53 ms event when they're allowed to, so whatever is holding them to 6.96 ms isn't a hardware ceiling.
"It's a factor of ability" doesn't fit.
This has been asked before and answered. In thread 774487, asked directly whether iOS limits packets per connection event to 4: "there is no 'limiting' going on as it is commonly understood ... We find that 4 is a more commonly true number than 6 or more some chipsets claim." In thread 770717, to a developer on iOS 18.2 running the same parameters we are: "iOS does not 'limit' the number of writes. It is just a factor of ability."
Both answers need the accessory to be the variable. Ours isn't — same board, same firmware, minutes apart, and two non-Apple hosts take it to 1000 kbps and hold it indefinitely. The only thing that changes is which OS is acting as central. We don't think this can be explained by chipset capability when the chipset is the one thing held constant.
It's airtime, not packet count.
The "4 packets per connection event" number people quote here is the wrong unit, and we think that's why these threads go nowhere. Within one regime, as PDUs per event go up, PDU size goes down and the airtime doesn't move:
iOS 9 PDUs @ 250.4 B -> 12.51 ms
10 PDUs @ 211.1 B -> 12.32 ms
11 PDUs @ 186.4 B -> 12.47 ms
macOS 5 PDUs @ 239.4 B -> 6.73 ms
6 PDUs @ 178.1 B -> 6.60 ms
Nothing is counting packets. The event closes on a clock. Count and airtime were the same measurement back when everything was 1M PHY and 27-byte PDUs — with 2M and DLE they aren't, and quoting a packet count now hides the mechanism instead of describing it.
The peripheral isn't the limiter.
The MD bit was set on the peripheral's last PDU in 2147 of 2148 connection events. It always had more data queued, and the central closed the event anyway.
This isn't a new report.
The same mechanism has been described here before. Thread 133092 (2019) reports macOS closing the connection event while the peripheral still has MD set — exactly what we measure. Thread 713349 reports "about 5 response packets per connection event," which is the same budget: 6.96 ms is 5 full-size PDUs. Thread 6025 reports a drop from 7 packets to 3. None of those received a reply.
We're not raising them to relitigate old threads. The point is that three independent reports arriving at the same number across several years, on different accessories, points at a property of the scheduler rather than of anyone's hardware.
On iOS, this looks like it changed in iOS 18.
macOS has apparently behaved this way for years, going by the threads above. On iOS it's recent. We have video and screen recordings of this same peripheral tested on iOS 17, documented at the time as running consistently at around 1000 kbps. The behaviour described here started appearing when we moved to iOS 18. The firmware and the negotiated parameters are the same now as they were then, which points at a change in radio scheduling rather than anything on our side.
What we're asking:
Is the per-event airtime budget deliberate? ADG §55.6 and QA1931 cover interval, latency and timeout only. Neither mentions connection event length.
Why do macOS and iOS give roughly half what Android and Windows give for the same accessory, and why can iOS reach 12.53 ms without staying there?
Did anything change in iOS 18 around connection event scheduling?
Is there anything we can do from the accessory or app side? We're already at 2M PHY, DLE 251, MTU 247 and the 15 ms floor.
If the answer is "design for a floor, not a peak" — what's the floor? Right now we plan for ~560 kbps on Apple and roughly double that everywhere else, and that decides what we can ship, and whether we can count on Apple devices as a reliable platform for our product.
Captures, recordings and analysis available if they're useful.
0
0
27