diff --git a/src/com/limelight/nvstream/NvAudioStream.java b/src/com/limelight/nvstream/NvAudioStream.java index d4f722e6..1d3b568e 100644 --- a/src/com/limelight/nvstream/NvAudioStream.java +++ b/src/com/limelight/nvstream/NvAudioStream.java @@ -3,29 +3,22 @@ package com.limelight.nvstream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.InetSocketAddress; import java.net.SocketException; -import java.nio.ByteBuffer; import java.util.concurrent.LinkedBlockingQueue; import jlibrtp.Participant; import jlibrtp.RTPSession; -import com.limelight.nvstream.av.AvBufferDescriptor; -import com.limelight.nvstream.av.AvBufferPool; -import com.limelight.nvstream.av.AvDecodeUnit; +import com.limelight.nvstream.av.AvByteBufferDescriptor; +import com.limelight.nvstream.av.AvByteBufferPool; import com.limelight.nvstream.av.AvRtpPacket; +import com.limelight.nvstream.av.AvShortBufferDescriptor; import com.limelight.nvstream.av.audio.AvAudioDepacketizer; import com.limelight.nvstream.av.audio.OpusDecoder; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; -import android.media.MediaCodec; -import android.media.MediaFormat; -import android.net.rtp.AudioGroup; -import android.net.rtp.AudioStream; -import android.view.Surface; public class NvAudioStream { public static final int RTP_PORT = 48000; @@ -40,7 +33,7 @@ public class NvAudioStream { private AvAudioDepacketizer depacketizer = new AvAudioDepacketizer(); - private AvBufferPool pool = new AvBufferPool(1500); + private AvByteBufferPool pool = new AvByteBufferPool(1500); public void startAudioStream(final String host) { @@ -147,7 +140,8 @@ public class NvAudioStream { public void run() { for (;;) { - short[] samples; + AvShortBufferDescriptor samples; + try { samples = depacketizer.getNextDecodedData(); } catch (InterruptedException e) { @@ -155,7 +149,7 @@ public class NvAudioStream { return; } - track.write(samples, 0, samples.length); + track.write(samples.data, samples.offset, samples.length); } } }).start(); @@ -168,7 +162,7 @@ public class NvAudioStream { @Override public void run() { DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500); - AvBufferDescriptor desc = new AvBufferDescriptor(null, 0, 0); + AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0); for (;;) { diff --git a/src/com/limelight/nvstream/NvVideoStream.java b/src/com/limelight/nvstream/NvVideoStream.java index 370d042c..2b1a8786 100644 --- a/src/com/limelight/nvstream/NvVideoStream.java +++ b/src/com/limelight/nvstream/NvVideoStream.java @@ -10,8 +10,8 @@ import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.concurrent.LinkedBlockingQueue; -import com.limelight.nvstream.av.AvBufferDescriptor; -import com.limelight.nvstream.av.AvBufferPool; +import com.limelight.nvstream.av.AvByteBufferDescriptor; +import com.limelight.nvstream.av.AvByteBufferPool; import com.limelight.nvstream.av.AvDecodeUnit; import com.limelight.nvstream.av.AvRtpPacket; import com.limelight.nvstream.av.video.AvVideoDepacketizer; @@ -37,7 +37,7 @@ public class NvVideoStream { private RTPSession session; private DatagramSocket rtp; - private AvBufferPool pool = new AvBufferPool(1500); + private AvByteBufferPool pool = new AvByteBufferPool(1500); private AvVideoDepacketizer depacketizer = new AvVideoDepacketizer(); @@ -176,7 +176,7 @@ public class NvVideoStream { buf.clear(); // Copy data from our buffer list into the input buffer - for (AvBufferDescriptor desc : du.getBufferList()) + for (AvByteBufferDescriptor desc : du.getBufferList()) { buf.put(desc.data, desc.offset, desc.length); @@ -234,7 +234,7 @@ public class NvVideoStream { @Override public void run() { DatagramPacket packet = new DatagramPacket(pool.allocate(), 1500); - AvBufferDescriptor desc = new AvBufferDescriptor(null, 0, 0); + AvByteBufferDescriptor desc = new AvByteBufferDescriptor(null, 0, 0); for (;;) { diff --git a/src/com/limelight/nvstream/av/AvBufferDescriptor.java b/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java similarity index 77% rename from src/com/limelight/nvstream/av/AvBufferDescriptor.java rename to src/com/limelight/nvstream/av/AvByteBufferDescriptor.java index e56da06f..2d6298f1 100644 --- a/src/com/limelight/nvstream/av/AvBufferDescriptor.java +++ b/src/com/limelight/nvstream/av/AvByteBufferDescriptor.java @@ -1,18 +1,18 @@ package com.limelight.nvstream.av; -public class AvBufferDescriptor { +public class AvByteBufferDescriptor { public byte[] data; public int offset; public int length; - public AvBufferDescriptor(byte[] data, int offset, int length) + public AvByteBufferDescriptor(byte[] data, int offset, int length) { this.data = data; this.offset = offset; this.length = length; } - public AvBufferDescriptor(AvBufferDescriptor desc) + public AvByteBufferDescriptor(AvByteBufferDescriptor desc) { this.data = desc.data; this.offset = desc.offset; diff --git a/src/com/limelight/nvstream/av/AvBufferPool.java b/src/com/limelight/nvstream/av/AvByteBufferPool.java similarity index 86% rename from src/com/limelight/nvstream/av/AvBufferPool.java rename to src/com/limelight/nvstream/av/AvByteBufferPool.java index d02c75eb..fae0cbe5 100644 --- a/src/com/limelight/nvstream/av/AvBufferPool.java +++ b/src/com/limelight/nvstream/av/AvByteBufferPool.java @@ -2,11 +2,11 @@ package com.limelight.nvstream.av; import java.util.LinkedList; -public class AvBufferPool { +public class AvByteBufferPool { private LinkedList bufferList = new LinkedList(); private int bufferSize; - public AvBufferPool(int size) + public AvByteBufferPool(int size) { this.bufferSize = size; } diff --git a/src/com/limelight/nvstream/av/AvDecodeUnit.java b/src/com/limelight/nvstream/av/AvDecodeUnit.java index 08ffe114..69300b83 100644 --- a/src/com/limelight/nvstream/av/AvDecodeUnit.java +++ b/src/com/limelight/nvstream/av/AvDecodeUnit.java @@ -8,11 +8,11 @@ public class AvDecodeUnit { public static final int TYPE_OPUS = 2; private int type; - private List bufferList; + private List bufferList; private int dataLength; private int flags; - public AvDecodeUnit(int type, List bufferList, int dataLength, int flags) + public AvDecodeUnit(int type, List bufferList, int dataLength, int flags) { this.type = type; this.bufferList = bufferList; @@ -30,7 +30,7 @@ public class AvDecodeUnit { return flags; } - public List getBufferList() + public List getBufferList() { return bufferList; } diff --git a/src/com/limelight/nvstream/av/AvRtpPacket.java b/src/com/limelight/nvstream/av/AvRtpPacket.java index f5354f79..ebd67c20 100644 --- a/src/com/limelight/nvstream/av/AvRtpPacket.java +++ b/src/com/limelight/nvstream/av/AvRtpPacket.java @@ -6,11 +6,11 @@ public class AvRtpPacket { private byte packetType; private short seqNum; - private AvBufferDescriptor buffer; + private AvByteBufferDescriptor buffer; - public AvRtpPacket(AvBufferDescriptor buffer) + public AvRtpPacket(AvByteBufferDescriptor buffer) { - this.buffer = new AvBufferDescriptor(buffer); + this.buffer = new AvByteBufferDescriptor(buffer); ByteBuffer bb = ByteBuffer.wrap(buffer.data, buffer.offset, buffer.length); @@ -34,8 +34,8 @@ public class AvRtpPacket { return seqNum; } - public AvBufferDescriptor getNewPayloadDescriptor() + public AvByteBufferDescriptor getNewPayloadDescriptor() { - return new AvBufferDescriptor(buffer.data, buffer.offset+12, buffer.length-12); + return new AvByteBufferDescriptor(buffer.data, buffer.offset+12, buffer.length-12); } } diff --git a/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java b/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java new file mode 100644 index 00000000..9d028326 --- /dev/null +++ b/src/com/limelight/nvstream/av/AvShortBufferDescriptor.java @@ -0,0 +1,21 @@ +package com.limelight.nvstream.av; + +public class AvShortBufferDescriptor { + public short[] data; + public int offset; + public int length; + + public AvShortBufferDescriptor(short[] data, int offset, int length) + { + this.data = data; + this.offset = offset; + this.length = length; + } + + public AvShortBufferDescriptor(AvShortBufferDescriptor desc) + { + this.data = desc.data; + this.offset = desc.offset; + this.length = desc.length; + } +} diff --git a/src/com/limelight/nvstream/av/AvShortBufferPool.java b/src/com/limelight/nvstream/av/AvShortBufferPool.java new file mode 100644 index 00000000..5e8cc043 --- /dev/null +++ b/src/com/limelight/nvstream/av/AvShortBufferPool.java @@ -0,0 +1,30 @@ +package com.limelight.nvstream.av; + +import java.util.LinkedList; + +public class AvShortBufferPool { + private LinkedList bufferList = new LinkedList(); + private int bufferSize; + + public AvShortBufferPool(int size) + { + this.bufferSize = size; + } + + public synchronized short[] allocate() + { + if (bufferList.isEmpty()) + { + return new short[bufferSize]; + } + else + { + return bufferList.removeFirst(); + } + } + + public synchronized void free(short[] buffer) + { + bufferList.addFirst(buffer); + } +} diff --git a/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java b/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java index 28c66752..1d67f721 100644 --- a/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java +++ b/src/com/limelight/nvstream/av/audio/AvAudioDepacketizer.java @@ -2,11 +2,16 @@ package com.limelight.nvstream.av.audio; import java.util.concurrent.LinkedBlockingQueue; -import com.limelight.nvstream.av.AvBufferDescriptor; +import com.limelight.nvstream.av.AvByteBufferDescriptor; import com.limelight.nvstream.av.AvRtpPacket; +import com.limelight.nvstream.av.AvShortBufferDescriptor; +import com.limelight.nvstream.av.AvShortBufferPool; public class AvAudioDepacketizer { - private LinkedBlockingQueue decodedUnits = new LinkedBlockingQueue(); + private LinkedBlockingQueue decodedUnits = + new LinkedBlockingQueue(); + + private AvShortBufferPool pool = new AvShortBufferPool(OpusDecoder.getMaxOutputShorts()); // Sequencing state private short lastSequenceNumber; @@ -34,25 +39,22 @@ public class AvAudioDepacketizer { lastSequenceNumber = seq; // This is all the depacketizing we need to do - AvBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); + AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); // Submit this data to the decoder - short[] pcmData = new short[OpusDecoder.getMaxOutputShorts()]; - + short[] pcmData = pool.allocate(); int decodeLen = OpusDecoder.decode(rtpPayload.data, rtpPayload.offset, rtpPayload.length, pcmData); - // Return value of decode is frames decoded per channel - decodeLen *= OpusDecoder.getChannelCount(); - if (decodeLen > 0) { - // Jank! - short[] trimmedPcmData = new short[decodeLen]; - System.arraycopy(pcmData, 0, trimmedPcmData, 0, decodeLen); - decodedUnits.add(trimmedPcmData); + // Return value of decode is frames decoded per channel + decodeLen *= OpusDecoder.getChannelCount(); + + // Put it on the decoded queue + decodedUnits.add(new AvShortBufferDescriptor(pcmData, 0, decodeLen)); } } - public short[] getNextDecodedData() throws InterruptedException + public AvShortBufferDescriptor getNextDecodedData() throws InterruptedException { return decodedUnits.take(); } diff --git a/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java b/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java index 8ae223c3..f1d063e1 100644 --- a/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java +++ b/src/com/limelight/nvstream/av/video/AvVideoDepacketizer.java @@ -3,7 +3,7 @@ package com.limelight.nvstream.av.video; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQueue; -import com.limelight.nvstream.av.AvBufferDescriptor; +import com.limelight.nvstream.av.AvByteBufferDescriptor; import com.limelight.nvstream.av.AvDecodeUnit; import com.limelight.nvstream.av.AvRtpPacket; @@ -12,7 +12,7 @@ import android.media.MediaCodec; public class AvVideoDepacketizer { // Current NAL state - private LinkedList avcNalDataChain = null; + private LinkedList avcNalDataChain = null; private int avcNalDataLength = 0; private int currentlyDecoding; @@ -29,8 +29,8 @@ public class AvVideoDepacketizer { int flags = 0; // Check if this is a special NAL unit - AvBufferDescriptor header = avcNalDataChain.getFirst(); - AvBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(header); + AvByteBufferDescriptor header = avcNalDataChain.getFirst(); + AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(header); if (specialSeq != null) { @@ -85,7 +85,7 @@ public class AvVideoDepacketizer { public void addInputData(AvVideoPacket packet) { - AvBufferDescriptor location = packet.getNewPayloadDescriptor(); + AvByteBufferDescriptor location = packet.getNewPayloadDescriptor(); while (location.length != 0) { @@ -93,7 +93,7 @@ public class AvVideoDepacketizer { int start = location.offset; // Check for a special sequence - AvBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(location); + AvByteBufferDescriptor specialSeq = NAL.getSpecialSequenceDescriptor(location); if (specialSeq != null) { if (NAL.isAvcStartSequence(specialSeq)) @@ -108,7 +108,7 @@ public class AvVideoDepacketizer { reassembleAvcNal(); // Setup state for the new NAL - avcNalDataChain = new LinkedList(); + avcNalDataChain = new LinkedList(); avcNalDataLength = 0; } } @@ -141,7 +141,7 @@ public class AvVideoDepacketizer { } } - AvBufferDescriptor data = new AvBufferDescriptor(location.data, start, location.offset-start); + AvByteBufferDescriptor data = new AvByteBufferDescriptor(location.data, start, location.offset-start); if (currentlyDecoding == AvDecodeUnit.TYPE_H264 && avcNalDataChain != null) { @@ -172,7 +172,7 @@ public class AvVideoDepacketizer { lastSequenceNumber = seq; // Pass the payload to the non-sequencing parser - AvBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); + AvByteBufferDescriptor rtpPayload = packet.getNewPayloadDescriptor(); addInputData(new AvVideoPacket(rtpPayload)); } @@ -185,7 +185,7 @@ public class AvVideoDepacketizer { class NAL { // This assumes that the buffer passed in is already a special sequence - public static boolean isAvcStartSequence(AvBufferDescriptor specialSeq) + public static boolean isAvcStartSequence(AvByteBufferDescriptor specialSeq) { if (specialSeq.length != 3 && specialSeq.length != 4) return false; @@ -195,7 +195,7 @@ class NAL { } // This assumes that the buffer passed in is already a special sequence - public static boolean isUnknownStartSequence(AvBufferDescriptor specialSeq) + public static boolean isUnknownStartSequence(AvByteBufferDescriptor specialSeq) { if (specialSeq.length != 3) return false; @@ -205,7 +205,7 @@ class NAL { } // This assumes that the buffer passed in is already a special sequence - public static boolean isAvcFrameStart(AvBufferDescriptor specialSeq) + public static boolean isAvcFrameStart(AvByteBufferDescriptor specialSeq) { if (specialSeq.length != 4) return false; @@ -215,7 +215,7 @@ class NAL { } // Returns a buffer descriptor describing the start sequence - public static AvBufferDescriptor getSpecialSequenceDescriptor(AvBufferDescriptor buffer) + public static AvByteBufferDescriptor getSpecialSequenceDescriptor(AvByteBufferDescriptor buffer) { // NAL start sequence is 00 00 00 01 or 00 00 01 if (buffer.length < 3) @@ -233,19 +233,19 @@ class NAL { buffer.data[buffer.offset+3] == 0x01) { // It's the AVC start sequence 00 00 00 01 - return new AvBufferDescriptor(buffer.data, buffer.offset, 4); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 4); } else { // It's 00 00 00 - return new AvBufferDescriptor(buffer.data, buffer.offset, 3); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3); } } else if (buffer.data[buffer.offset+2] == 0x01 || buffer.data[buffer.offset+2] == 0x02) { // These are easy: 00 00 01 or 00 00 02 - return new AvBufferDescriptor(buffer.data, buffer.offset, 3); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3); } else if (buffer.data[buffer.offset+2] == 0x03) { @@ -267,7 +267,7 @@ class NAL { else { // It's not a standard replacement so it's a special sequence - return new AvBufferDescriptor(buffer.data, buffer.offset, 3); + return new AvByteBufferDescriptor(buffer.data, buffer.offset, 3); } } } diff --git a/src/com/limelight/nvstream/av/video/AvVideoPacket.java b/src/com/limelight/nvstream/av/video/AvVideoPacket.java index b847be83..d2bd8445 100644 --- a/src/com/limelight/nvstream/av/video/AvVideoPacket.java +++ b/src/com/limelight/nvstream/av/video/AvVideoPacket.java @@ -1,17 +1,17 @@ package com.limelight.nvstream.av.video; -import com.limelight.nvstream.av.AvBufferDescriptor; +import com.limelight.nvstream.av.AvByteBufferDescriptor; public class AvVideoPacket { - private AvBufferDescriptor buffer; + private AvByteBufferDescriptor buffer; - public AvVideoPacket(AvBufferDescriptor rtpPayload) + public AvVideoPacket(AvByteBufferDescriptor rtpPayload) { - buffer = new AvBufferDescriptor(rtpPayload); + buffer = new AvByteBufferDescriptor(rtpPayload); } - public AvBufferDescriptor getNewPayloadDescriptor() + public AvByteBufferDescriptor getNewPayloadDescriptor() { - return new AvBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56); + return new AvByteBufferDescriptor(buffer.data, buffer.offset+56, buffer.length-56); } }