Forward Error Correction (FEC) in UDP isn’t about recovering lost packets, it’s about making the data within those packets recoverable even if the packet itself is gone.
Let’s see it in action. Imagine a video stream. If a packet is lost, without FEC, a frame might glitch or freeze. With FEC, we can send redundant information that allows the receiver to reconstruct the missing data.
Here’s a simplified UDP packet with FEC:
Original Data Packet:
[ Header | Data Block A ]
FEC Packet:
[ Header | FEC Data (derived from A) ]
The receiver gets multiple packets. If one data packet is lost, it can use the FEC packet(s) to mathematically recreate the missing Data Block A. This is typically done using techniques like Reed-Solomon codes. The FEC data is essentially a checksum that’s sophisticated enough to reconstruct multiple missing pieces of data.
The core problem FEC solves for UDP is the inherent unreliability of UDP. UDP doesn’t guarantee delivery, order, or integrity. For applications like real-time video, audio, or gaming, the latency introduced by TCP’s retransmissions is unacceptable. FEC provides a way to tolerate a certain level of packet loss without the delay penalty of retransmission.
Internally, FEC works by encoding a block of data into a larger set of symbols. This larger set is then transmitted. The redundancy is calculated such that if a certain number of symbols are lost, the original data can still be recovered. For example, a (15, 10) Reed-Solomon code means you send 15 symbols, and if any 10 of them are received, you can perfectly reconstruct the original 10 symbols. This means you can tolerate 5 lost symbols out of the 15 transmitted.
The key levers you control with FEC are the code rate and the packetization scheme.
The code rate is the ratio of original data symbols to total transmitted symbols (e.g., 10/15 in the example above). A lower code rate (more redundancy) offers better protection against loss but increases bandwidth usage. A higher code rate uses less bandwidth but can only tolerate less loss.
The packetization scheme refers to how you group your original data into blocks for FEC encoding and how you interleave these blocks across multiple UDP packets. You might group 100 bytes of data and generate FEC for it, then send that FEC data in a separate UDP packet. Or, you might interleave data from multiple sources into a single FEC block.
A common, but often overlooked, aspect of FEC implementation is the overhead of the FEC symbols themselves. While FEC allows you to recover data, the FEC symbols themselves are additional data that must be transmitted. If your network is already saturated, adding FEC can push it over the edge, leading to more packet loss, thus defeating the purpose. The FEC symbols are not "free" data; they consume bandwidth.
The next challenge you’ll face is how to intelligently decide when to apply FEC and how much redundancy to use, adapting to changing network conditions.