The 10-Minute Stutter: When a Wi-Fi Group Rekey Freezes Game Streaming

I stream games from my PC to a Raspberry Pi 4 with Sunshine and Moonlight: 1080p, 144 fps, 40 Mbit/s. It worked well, except that every so often the picture froze for one or two seconds and then caught up. It felt random.
It wasn’t random. It happened every ten minutes, to the second. This post is about how I found that out, why it happens, and a few wrong turns on the way.
The first clue: more bandwidth changed nothing
My first guess was bandwidth, so I raised the bitrate from 40 to 50 Mbit/s. Nothing changed: no better, no worse.
That turned out to be the most useful result of the evening. A bandwidth problem gets worse when you ask for more bandwidth. This one didn’t care. So whatever was happening wasn’t about capacity; something was interrupting the stream outright.
Looking at the host first, and finding nothing
The PC runs Sunshine, so I started there:
- Encoder resets? Sunshine logs one when it recreates or tears down an encoder. The session log was empty for the whole 48 minutes.
- Display mode or HDR change? That would log an encoder re-enumeration. Absent.
- A dropped session? One connect, one disconnect, 48 minutes apart.
- Something else using the GPU? I run local AI models on the same machine. Nothing had run for days.
- Windows itself? System, application, update, thermal and network logs were all silent around the time of a stutter.
The silence was the finding. Nothing on the host went wrong, so the host never noticed. Whatever was happening, it happened after the packets left the PC.
The pattern
On the Pi, wpa_supplicant (the program that handles Wi-Fi authentication) logs a line like this:
wpa_supplicant[731]: wlan0: WPA: Group rekeying completed with xx:xx:xx:xx:xx:xx [GTK=CCMP]
There were 131 of them in one day, every 600 seconds: at HH:09:08, HH:19:08, HH:29:08, and so on. The day before showed the same rhythm. I had noted one stutter as “somewhere between 20:59 and 21:01”, and the log had a rekey at 20:59:08.
Ten minutes is my router’s default interval for renewing the group key. On some firmware versions it can’t even be changed.
Why a group rekey hits a unicast stream
At first this shouldn’t make sense. WPA2 has two kinds of keys:
- The pairwise key (PTK) is negotiated with each client when it connects. It encrypts everything sent to that client specifically, which here is the whole video stream.
- The group key (GTK) is one key shared by every device on the access point. It is only used for broadcast and multicast. It gets rotated regularly because a device that has left the network still holds a working copy; rotating it quietly locks them out.
A group rekey replaces the group key and leaves the pairwise key alone. The video uses the pairwise key. In theory it never notices.
It notices here because of the Pi’s radio. The Pi 4’s onboard Wi-Fi is a Broadcom BCM43455, driven by the brcmfmac driver. It is a fullmac chip: the Wi-Fi state machine and the encryption engine run in closed firmware on the chip, not in the Linux driver. Installing a new key isn’t a quick write to kernel memory. It is a command sent down to that firmware, which reconfigures its encryption hardware and stalls the whole radio for a moment, unicast traffic included. This is a long-known quirk of the chip, not a misconfiguration.
To be precise about what I know: the timing match is mine and it is exact. The firmware stall is the documented behaviour of this chip; I didn’t measure it on my Pi.
Why a 100 ms hiccup becomes a 2-second freeze
The stall itself is short. What you see is the recovery:
group rekey → the Pi's Wi-Fi firmware stalls the radio (~100 ms)
→ video packets are lost
→ the decoder can't rebuild the frame
→ Moonlight asks Sunshine for a fresh keyframe
→ Sunshine encodes and sends one (keyframes are large, so this takes a while)
→ the picture unfreezes
Until a full keyframe arrives, the last good frame stays on screen. That round trip is the one-to-two seconds.
A wrong turn worth sharing
My network has a router and a mesh repeater. Scanning from the Pi showed five access points (one per radio), and I assigned them to the wrong devices. That led me to “the Pi is on the router’s weaker radio; pin it to another channel”. That would have moved a working link onto a channel where the router may have to switch away whenever radar shows up (a DFS channel), for no gain.
Two things misled me:
- The network name was carried over from an older router, so the name suggested different hardware than what is actually installed.
- Both devices are from the same vendor, so the hardware ID at the start of each MAC address didn’t tell them apart either.
The router’s own mesh overview settled it at a glance: the device with three radios is the tri-band repeater, and the Pi is connected to it. Lesson: look at the router’s view of the network before you reason from a scan list.
The negative result that mattered most
The mesh overview had one more number: the Pi’s link ran at 433 Mbit/s. That is exactly the maximum for a single-antenna 802.11ac chip like the BCM43455. The Pi was already connected as well as its hardware allows.
That ruled out a whole category of fixes. Better placement, another channel or a stronger signal cannot help a link that is already at its ceiling. The freeze was never a signal problem.
The rest of the Pi was healthy, too: no throttling, no under-voltage, 56 °C at full clock, no disconnects or roams during the session.
The fix: take the Pi’s radio out of the path
The repeater has a LAN port and stands two metres from the Pi. So the fix is a cable from the Pi to the repeater:
before: PC ──cable──► router ──Wi-Fi──► repeater ──Wi-Fi──► Pi
after: PC ──cable──► router ──Wi-Fi──► repeater ──cable──► Pi
The argument isn’t “wired is better”. It is more specific: the stall happens on the Pi’s own Wi-Fi chip, when it installs the new group key. Take that radio out of the path and nothing on the Pi installs a group key at all. The repeater still rekeys with the router, but that is different hardware, which doesn’t stall its traffic the way this chip does. The remaining wireless hop is the repeater’s fast backhaul on its own dedicated radio.
Once the cable works, I’ll also switch the Pi’s Wi-Fi off (rfkill block wifi), so it stops keeping a second, wireless connection alive next to the cable. Check that the wired interface is up with an address first, or you will lock yourself out of a headless Pi.
To confirm the fix, watch the clock: if the minutes ending in 9 stay clean, it’s done.
Status: at the time of writing I have the diagnosis and the plan but haven’t run the cable yet. I’ll update this post with the result.
Update: a movie night that didn’t fit
A few weeks later I watched a 70-minute movie over the same stream, and the freezes felt more frequent: every five minutes or so. So I went back to the logs.
- Sunshine had one connect and one disconnect, 70 minutes apart, and nothing in between. Again, the host saw nothing.
- The Pi logged a group rekey every ten minutes, seven of them during the movie, and nothing else: no reconnects, no roaming, no errors.
So the rekeys alone can’t explain a freeze every five minutes; half of them would land on nothing. One thing was different from the first investigation, though: Bluetooth earbuds were connected to the Pi for the movie’s sound. On the Pi 4, Wi-Fi and Bluetooth live on the same chip and share one antenna. While Bluetooth audio is streaming, the two take turns on the radio, which is a well-known source of Wi-Fi hiccups on this hardware.
I can’t prove that link. Neither Sunshine at its default log level nor Moonlight records the freezes themselves, so I have the timestamps of the rekeys but not of the stutters. What I can say is that the cable covers both suspects: with the stream on Ethernet, neither a key change nor Bluetooth sharing the antenna can touch it.
For the next test I’ll raise Sunshine’s log level to Debug, which logs dropped and late frames, and watch one session with the earbuds and one without.
If a cable is impossible in your setup, the remaining levers are weaker. You can raise or disable the group key interval in the router’s Wi-Fi security settings, if your firmware shows it. You can also lower the stream’s frame rate, which doesn’t fix the rekey but makes the recovery a little faster.
Things I deliberately didn’t change
The PC has the usual power-saving settings switched on: PCIe link power management, the network card’s “green Ethernet” features, the Balanced power plan. Any of them could plausibly cause some streaming hiccup, and I’ll turn them off eventually.
But not now. Change them together with the cable and you’ll never know which one mattered.
Takeaways
- “Random” stutters are worth timestamping. Ten minutes on the dot is a strong hint, and you only see it in a log.
- A fix that changes nothing is information. More bandwidth not helping ruled out half the suspects.
- Check whether the link is already at its ceiling before you tune Wi-Fi.
- Know your chip. On fullmac Wi-Fi like the Pi’s, key handling lives in firmware, and “this shouldn’t affect unicast” isn’t guaranteed.
- If Sunshine stutters and the timing doesn’t fit a pattern like this, raise its log level first: dropped and late frames are only logged at Debug.