A junior engineer wiring up voice chat reaches for Spring Boot’s
@EnableWebSocketand wraps everything in TCP. It works on their laptop with two friends. Ship it.Then reality hits: voice audio is 20ms Opus frames arriving at 50 packets/second per user. At 10,000 concurrent speakers that’s 500,000 packets/sec. TCP’s retransmit-and-wait semantic — built for reliability — becomes your enemy. A single dropped packet stalls the receive buffer until the OS retransmits. You hear a half-second freeze. Every. Single. Time.
WebRTC doesn’t use TCP for media. It uses UDP. Not because UDP is “faster” in some hand-wavy sense, but because for real-time media a stale packet is worse than no packet. If an Opus frame is 20ms late, you don’t want it. You want to interpolate silence and move on.
Spring Boot hides this. It gives you a nice
WebSocketHandler, aTextMessage, and zero control over the transport layer beneath it. You cannot drop into raw UDP. You cannot tune socket receive buffers. You cannot implement DTLS yourself. You are building audio on top of a framework that was never designed for it.
Here’s what a naive UDP server looks like in Java before this lesson:
One thread. Blocking receive. This hits the OS kernel’s receive buffer at ~50K packets/sec on a modern NIC. Anything beyond that gets silently dropped — no exception, no log. It just disappears.
Scale this: spawn a thread per client. 10,000 clients = 10,000 OS threads. At 1MB stack each, that’s 10GB of virtual address space before you’ve processed a single byte of audio. The OS scheduler starts spending more time context-switching than running your code.
The second failure:
new byte[1500]inside the receive loop. Each UDP packet allocation goes to the JVM Eden space. At 500K packets/sec that’s 750MB/sec of allocation pressure. The GC fires a minor collection every few hundred milliseconds. During that pause — which lasts 5–50ms on a busy heap — your receive loop stops. The OS kernel’s socket receive buffer fills up. UDP packets are dropped. Users hear glitches.You cannot afford GC pauses in a media path.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.