· via dev.to (home feed)
AWDL radio scheduling behind recurring 528 ms stutter that looks like an app bug
A dev.to post traces a recurring 528 ms stutter in a MultipeerConnectivity app to AWDL's 524 ms availability windows, explaining why the radio's duty cycle masquerades as an application bug.
A stutter that wasn't in the app
A developer writing on dev.to has documented a week-long debugging chase after a pointer in their screen-sharing app, ExtendPilot, froze briefly and repeatedly. The app mirrors a Mac display to iPhones and iPads over peer-to-peer Wi-Fi, and everyone who tried it noticed the stutter before anything else. After searching their own code without success, the team traced the pauses to the radio itself behaving as designed: Apple Wireless Direct Link, the peer-to-peer Wi-Fi layer that carries AirDrop, AirPlay and MultipeerConnectivity, goes off the air on a fixed schedule.
The numbers ruled out self-inflicted congestion
The first suspect was the app's own video stream, which accounts for more than 99% of its traffic. Correlating host and viewer logs on a shared sequence number showed the opposite: in the 300 ms before a typical stall, the median amount of video sent was 3 KB, roughly 0.08 Mbit/s, about twenty times below the 1.58 Mbit/s the link carried on average. The pauses were not the app competing with itself.
The intervals were the giveaway. Across 97 episodes, the gaps between stalls read 528, 528, 528, 512, 528, 528, with a median of 528 ms. Interference and contention arrive in bursts, whereas a gap that repeats to within milliseconds points to a clock. AWDL synchronises its peers on a period of 512 TU, and a TU in the 802.11 specification is 1,024 microseconds, putting the period at 524.288 ms. The measured 528 ms matches closely enough that, according to the post, the stalls are the radio's own availability windows, with packets queuing until the next one opens. Nothing is dropped and nothing is retried, which is why every loss metric reported a healthy link.
Why AWDL goes quiet at all
AWDL channel-hops. A device has a single antenna and time-slices it between the infrastructure channel a router uses and the AWDL social channel where peers discover each other. Peers agree on a schedule so they are awake at the same moments; between those moments the peer-to-peer link effectively does not exist. That is how one radio serves two networks at once, but it means periodic latency spikes are inherent to peer-to-peer Wi-Fi, and any protocol layered on top inherits them.
Three reasons it masquerades as an application bug
First, apps do not choose the radio. MultipeerConnectivity on macOS can select infrastructure Wi-Fi, AWDL or Ethernet, and no API reports the decision, so identical code on the same devices can behave differently when the underlying link changes.
Second, reliable delivery hides the gap and then releases a burst. Because .reliable sends are ordered, frames caught by a 300 ms radio absence are queued and delivered as a batch the moment the window opens — visible as a freeze followed by a catch-up, while the delivery ratio stays near 99%.
Third, the delay distribution is bimodal. Half of packets arrived within 4 ms of the best transit ever measured, and 15% arrived more than 120 ms behind it, with little in between. A mean computed over both populations describes neither and looks unremarkable.
Absorbing it rather than fixing it
No flag, priority class or API can keep the radio awake on an app's behalf. The developer's answer was a jitter buffer that holds arriving data briefly and plays it out on the sender's clock. An adaptive buffer of 50–160 ms cut frozen pointer frames from 12.8% to 2.7%, at the cost of up to 160 ms of added latency. The stalls still occur exactly as often; the fix makes them invisible rather than repairing them. Moving video to a separate Network.framework lane would not help either, since both lanes share the same radio.
The post also offers diagnostics. On the Mac, netstat -I awdl0 -w 1 during a live session shows whether AWDL is carrying the traffic, and running the same session twice — once with the phone's Wi-Fi off, once joined to the same SSID — acts as a crude A/B test. Retries should not fire near the radio's period: a flat 150 ms recovery interval once generated 360 requests in 107 seconds, each adding load. Buffers should adapt asymmetrically, rising fast and decaying slowly, in the manner of TCP's AIMD. The author notes the measurements come from one device pair and 60-second runs; the 528 ms figure is theirs, but the 512 TU period belongs to AWDL itself.
Why it matters
AWDL is barely documented, and any developer building realtime features on MultipeerConnectivity will meet this behaviour, most likely assuming they shipped a bug. The post shows the failure is structural: the framework silently switches transports, reliability queues mask the gaps, and standard delivery metrics cannot see them. Knowing that a roughly half-second pause can be a scheduled property of the link — and that jitter buffering, not retries or tuning, is the available response — turns a mystery into a design constraint.
- #awdl
- #multipeer-connectivity
- #apple
- #networking
- #latency