Use ring buffers for audio and video handling to remove the last large allocations that were happening very frequently

This commit is contained in:
Cameron Gutman 2014-03-17 13:38:49 -04:00
parent a39f4c5eab
commit 8c9d0d171c
2 changed files with 35 additions and 7 deletions

View File

@ -12,9 +12,14 @@ public class AudioDepacketizer {
private LinkedBlockingQueue<ByteBufferDescriptor> decodedUnits = private LinkedBlockingQueue<ByteBufferDescriptor> decodedUnits =
new LinkedBlockingQueue<ByteBufferDescriptor>(DU_LIMIT); new LinkedBlockingQueue<ByteBufferDescriptor>(DU_LIMIT);
// Direct submit state
private AudioRenderer directSubmitRenderer; private AudioRenderer directSubmitRenderer;
private byte[] directSubmitData; private byte[] directSubmitData;
// Non-direct submit state
private byte[][] pcmRing;
private int ringIndex;
// Sequencing state // Sequencing state
private short lastSequenceNumber; private short lastSequenceNumber;
@ -24,6 +29,9 @@ public class AudioDepacketizer {
if (directSubmitRenderer != null) { if (directSubmitRenderer != null) {
this.directSubmitData = new byte[OpusDecoder.getMaxOutputShorts()*2]; this.directSubmitData = new byte[OpusDecoder.getMaxOutputShorts()*2];
} }
else {
pcmRing = new byte[DU_LIMIT][OpusDecoder.getMaxOutputShorts()*2];
}
} }
private void decodeData(byte[] data, int off, int len) private void decodeData(byte[] data, int off, int len)
@ -36,11 +44,11 @@ public class AudioDepacketizer {
decodeLen = OpusDecoder.decode(data, off, len, directSubmitData); decodeLen = OpusDecoder.decode(data, off, len, directSubmitData);
} }
else { else {
pcmData = new byte[OpusDecoder.getMaxOutputShorts()*2]; pcmData = pcmRing[ringIndex];
decodeLen = OpusDecoder.decode(data, off, len, pcmData); decodeLen = OpusDecoder.decode(data, off, len, pcmData);
ringIndex = (ringIndex + 1) % DU_LIMIT;
} }
if (decodeLen > 0) { if (decodeLen > 0) {
// Return value of decode is frames (shorts) decoded per channel // Return value of decode is frames (shorts) decoded per channel
decodeLen *= 2*OpusDecoder.getChannelCount(); decodeLen *= 2*OpusDecoder.getChannelCount();

View File

@ -24,8 +24,14 @@ public class VideoStream {
public static final int FIRST_FRAME_TIMEOUT = 5000; public static final int FIRST_FRAME_TIMEOUT = 5000;
public static final int RTP_RECV_BUFFER = 128 * 1024; public static final int RTP_RECV_BUFFER = 128 * 1024;
public static final int MAX_PACKET_SIZE = 1050; public static final int MAX_PACKET_SIZE = 1050;
// The ring size MUST be greater than or equal to
// the maximum number of packets in a fully
// presentable frame
public static final int VIDEO_RING_SIZE = 192;
private InetAddress host; private InetAddress host;
private DatagramSocket rtp; private DatagramSocket rtp;
private Socket firstFrameSocket; private Socket firstFrameSocket;
@ -211,22 +217,36 @@ public class VideoStream {
Thread t = new Thread() { Thread t = new Thread() {
@Override @Override
public void run() { public void run() {
ByteBufferDescriptor desc = new ByteBufferDescriptor(new byte[MAX_PACKET_SIZE], 0, MAX_PACKET_SIZE); ByteBufferDescriptor ring[] = new ByteBufferDescriptor[VIDEO_RING_SIZE];
DatagramPacket packet = new DatagramPacket(desc.data, desc.length); int ringIndex = 0;
// Preinitialize the ring buffer
for (int i = 0; i < VIDEO_RING_SIZE; i++) {
ring[i] = new ByteBufferDescriptor(new byte[MAX_PACKET_SIZE], 0, MAX_PACKET_SIZE);
}
ByteBufferDescriptor desc;
DatagramPacket packet = new DatagramPacket(new byte[1], 1); // Placeholder array
while (!isInterrupted()) while (!isInterrupted())
{ {
try { try {
// Pull the next buffer in the ring and reset it
desc = ring[ringIndex];
desc.length = MAX_PACKET_SIZE;
desc.offset = 0;
// Read the video data off the network
packet.setData(desc.data, desc.offset, desc.length);
rtp.receive(packet); rtp.receive(packet);
// Submit video data to the depacketizer
desc.length = packet.getLength(); desc.length = packet.getLength();
depacketizer.addInputData(new RtpPacket(desc)); depacketizer.addInputData(new RtpPacket(desc));
desc.reinitialize(new byte[MAX_PACKET_SIZE], 0, MAX_PACKET_SIZE); ringIndex = (ringIndex + 1) % VIDEO_RING_SIZE;
packet.setData(desc.data, desc.offset, desc.length);
} catch (IOException e) { } catch (IOException e) {
listener.connectionTerminated(e); listener.connectionTerminated(e);
return; return;
} }
} }
} }
}; };