A recent project required the decryption of an
MPEG TS multicast stream.
The first attempt simply looped, reading from a
MulticastChannel , decrypting with a
Cipher and writing via a
DatagramChannel.
The decryption turned out to have negligible cost, which was surprising.
Unfortunately, this simple implementation dropped too many packets. The resultant video was unwatchable, being riddled with artifacts.
Some buffering was obviously required.
The standard
j.u.c classes did not resolve the problem. Packet loss remained a problem, perhaps due to the ongoing garbage collection.
The
LMAX Disruptor provides a ring buffer containing preallocated elements, eliminating GC.
Its design provides very small and consistency latency,
orders of magnitude better than
ArrayBlockingQueue.
A simple two thread design turned out to suffice :
- Blocking read packet into ByteBuffer in the ring buffer
- Decrypt ByteBuffer in-place and transmit from the ring buffer.
This approach generates zero garbage.
Any other design caused packet loss. That includes separating the decryption into a third thread.
The scheduling of the reading thread appears to be be the primary factor in avoiding packet loss. The system thus works best when there are more free cores than active threads. Further improvement would require manipulation of the scheduler, e.g. by pinning the thread to a specific core.
The result was very pleasing, requiring less than 100 LOSC.
A quad core 3.5 GHz Xeon suffices to handle four 1080P 30 Hz signals encrypted using AES-128.