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 =
new LinkedBlockingQueue<ByteBufferDescriptor>(DU_LIMIT);
// Direct submit state
private AudioRenderer directSubmitRenderer;
private byte[] directSubmitData;
// Non-direct submit state
private byte[][] pcmRing;
private int ringIndex;
// Sequencing state
private short lastSequenceNumber;
@ -24,6 +29,9 @@ public class AudioDepacketizer {
if (directSubmitRenderer != null) {
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)
@ -36,11 +44,11 @@ public class AudioDepacketizer {
decodeLen = OpusDecoder.decode(data, off, len, directSubmitData);
}
else {
pcmData = new byte[OpusDecoder.getMaxOutputShorts()*2];
pcmData = pcmRing[ringIndex];
decodeLen = OpusDecoder.decode(data, off, len, pcmData);
ringIndex = (ringIndex + 1) % DU_LIMIT;
}
if (decodeLen > 0) {
// Return value of decode is frames (shorts) decoded per channel
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 RTP_RECV_BUFFER = 128 * 1024;
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 DatagramSocket rtp;
private Socket firstFrameSocket;
@ -211,22 +217,36 @@ public class VideoStream {
Thread t = new Thread() {
@Override
public void run() {
ByteBufferDescriptor desc = new ByteBufferDescriptor(new byte[MAX_PACKET_SIZE], 0, MAX_PACKET_SIZE);
DatagramPacket packet = new DatagramPacket(desc.data, desc.length);
ByteBufferDescriptor ring[] = new ByteBufferDescriptor[VIDEO_RING_SIZE];
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())
{
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);
// Submit video data to the depacketizer
desc.length = packet.getLength();
depacketizer.addInputData(new RtpPacket(desc));
desc.reinitialize(new byte[MAX_PACKET_SIZE], 0, MAX_PACKET_SIZE);
packet.setData(desc.data, desc.offset, desc.length);
ringIndex = (ringIndex + 1) % VIDEO_RING_SIZE;
} catch (IOException e) {
listener.connectionTerminated(e);
return;
}
}
}
};