# HG changeset patch # User nikita@nikita-laptop # Date 1264281583 -3600 # Node ID e8d6255306f84575fcba1fc7c65abfa83d0cd1db # Parent f5a5d9237d69f0b865899064cfa361547394a9bd Sipdroid Basic diff -r f5a5d9237d69 -r e8d6255306f8 src/com/beem/project/beem/jingle/JingleService.java --- a/src/com/beem/project/beem/jingle/JingleService.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/com/beem/project/beem/jingle/JingleService.java Sat Jan 23 22:19:43 2010 +0100 @@ -57,7 +57,6 @@ import org.jivesoftware.smackx.jingle.media.PayloadType; import org.jivesoftware.smackx.jingle.nat.BasicTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; -import org.sipdroid.media.codecs.CodecManager; import android.content.Context; import android.net.Uri; diff -r f5a5d9237d69 -r e8d6255306f8 src/com/beem/project/beem/jingle/RTPAudioSession.java --- a/src/com/beem/project/beem/jingle/RTPAudioSession.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/com/beem/project/beem/jingle/RTPAudioSession.java Sat Jan 23 22:19:43 2010 +0100 @@ -1,15 +1,11 @@ package com.beem.project.beem.jingle; -import jlibrtp.Participant; -import jlibrtp.RTPSession; - import org.jivesoftware.smackx.jingle.JingleSession; import org.jivesoftware.smackx.jingle.media.JingleMediaSession; import org.jivesoftware.smackx.jingle.media.PayloadType; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; import org.sipdroid.media.RtpStreamReceiver; import org.sipdroid.media.RtpStreamSender; -import org.sipdroid.media.codecs.CodecManager; import org.sipdroid.net.SipdroidSocket; import android.content.Context; @@ -97,11 +93,7 @@ rtpSocket = new SipdroidSocket(src_port); rtcpSocket = new SipdroidSocket(src_port + 1); } catch (Exception e) { + e.printStackTrace(); } - rtpSession = new RTPSession(rtpSocket, rtcpSocket); - Participant p = new Participant(dest_addr,dest_port, dest_port + 1); - rtpSession.addParticipant(p); - rtpSession.naivePktReception(true); - rtpSession.packetBufferBehavior(3); } } diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/AppCallerThread.java --- a/src/jlibrtp/AppCallerThread.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.util.Enumeration; - -/** - * The purpose of this thread is to check whether there are packets ready from - * any participants. - * - * It should sleep when not in use, and be woken up by a condition variable. - * - * Optionally, if we do jitter-control, the condition variable should have a max - * waiting period equal to how often we need to push data. - * - * @author Arne Kepp - */ -public class AppCallerThread extends Thread { - /** The parent RTP Session */ - RTPSession rtpSession; - /** The applications interface, where the callback methods are called */ - RTPAppIntf appl; - - /** - * Instatiates the AppCallerThread - * - * @param session - * the RTPSession with participants etc - * @param rtpApp - * the interface to which data is given - */ - protected AppCallerThread(RTPSession session, RTPAppIntf rtpApp) { - rtpSession = session; - appl = rtpApp; - if (RTPSession.rtpDebugLevel > 1) { - System.out.println("<-> AppCallerThread created"); - } - } - - /** - * The AppCallerThread will run in this loop until the RTPSession is - * terminated. - * - * Whenever an RTP packet is received it will loop over the participants to - * check for packet buffers that have available frame. - */ - public void run() { - if (RTPSession.rtpDebugLevel > 3) { - System.out.println("-> AppCallerThread.run()"); - } - - while (rtpSession.endSession == false) { - - rtpSession.pktBufLock.lock(); - try { - if (RTPSession.rtpDebugLevel > 4) { - System.out.println("<-> AppCallerThread going to Sleep"); - } - - try { - rtpSession.pktBufDataReady.await(); - } catch (Exception e) { - System.out.println("AppCallerThread:" + e.getMessage()); - } - - // Next loop over all participants and check whether they have - // anything for us. - Enumeration enu = rtpSession.partDb - .getParticipants(); - - while (enu.hasMoreElements()) { - Participant p = enu.nextElement(); - - boolean done = false; - // System.out.println(p.ssrc + " " + !done +" " + - // p.rtpAddress - // + " " + rtpSession.naiveReception + " " + p.pktBuffer); - // System.out.println("done: " + done + " p.unexpected: " + - // p.unexpected); - while (!done - && (!p.unexpected || rtpSession.naiveReception) - && p.pktBuffer != null && p.pktBuffer.length > 0) { - - DataFrame aFrame = p.pktBuffer.popOldestFrame(); - if (aFrame == null) { - done = true; - } else { - appl.receiveData(aFrame, p); - } - } - } - - } finally { - rtpSession.pktBufLock.unlock(); - } - } - if (RTPSession.rtpDebugLevel > 3) { - System.out.println("<- AppCallerThread.run() terminating"); - } - } - - public DataFrame getNextDataFrame() { - if (RTPSession.rtpDebugLevel > 3) { - System.out.println("-> AppCallerThread.run()"); - } - //rtpSession.pktBufLock.lock(); - try { - if (RTPSession.rtpDebugLevel > 4) { - System.out.println("<-> AppCallerThread going to Sleep"); - } - - /*try { - rtpSession.pktBufDataReady.await(); - } catch (Exception e) { - System.out.println("AppCallerThread:" + e.getMessage()); - }*/ - - // Next loop over all participants and check whether they have - // anything for us. - /*Enumeration enu = rtpSession.partDb - .getParticipants(); - - while (enu.hasMoreElements()) {*/ - Participant p = rtpSession.firstPart; - - boolean done = false; - // System.out.println(p.ssrc + " " + !done +" " + - // p.rtpAddress - // + " " + rtpSession.naiveReception + " " + p.pktBuffer); - // System.out.println("done: " + done + " p.unexpected: " + - // p.unexpected); - while (!done - && (!p.unexpected || rtpSession.naiveReception) - && p.pktBuffer != null && p.pktBuffer.length > 0) { - - DataFrame aFrame = p.pktBuffer.popOldestFrame(); - if (aFrame == null) { - done = true; - } else { - return aFrame; - } - } - //} - - } finally { - //rtpSession.pktBufLock.unlock(); - } - if (RTPSession.rtpDebugLevel > 3) { - System.out.println("<- AppCallerThread.run() terminating"); - } - return null; - } - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/CompRtcpPkt.java --- a/src/jlibrtp/CompRtcpPkt.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.InetSocketAddress; -import java.util.LinkedList; -import java.util.ListIterator; - -/** - * Compound RTCP packet class. - * - * It basically holds a list of packets. This list can either be constructed by - * providing a byte[] of a compound packet, or by adding individual packets. - * - * Upon encode(), the packet will call encode on all the added packets. - * - * problem == 0 indicates the parsing succeeded. - * - * - * @author Arne Kepp - */ - -public class CompRtcpPkt { - /** Problem indicator, negative values denote packet type that cause problem */ - protected int problem = 0; - /** - * Stores the different subclasses of RtcpPkt that make up the compound - * packet - */ - protected LinkedList rtcpPkts = new LinkedList(); - - /** - * Instantiates an empty Compound RTCP packet to which you can add RTCP - * packets - */ - protected CompRtcpPkt() { - // Will have to add packets directly to rtcpPkts. - if (RTPSession.rtpDebugLevel > 7) { - System.out.println("<-> CompRtcpPkt()"); - } - } - - /** - * Add a RTCP packet to the compound packet. Pakcets are added in order, so - * you have to ensure that a Sender Report or Receiver Report is added - * first. - * - * @param aPkt - * the packet to be added - */ - protected void addPacket(RtcpPkt aPkt) { - if (RTPSession.rtpDebugLevel > 11) { - System.out.println(" <-> CompRtcpPkt.addPacket( " - + aPkt.getClass() + " )"); - } - - if (aPkt.problem == 0) { - rtcpPkts.add(aPkt); - } else { - this.problem = aPkt.problem; - } - } - - /** - * Picks a received Compound RTCP packet apart. - * - * Only SDES packets are processed directly, other packets are parsed and - * put into aComptRtcpPkt.rtcpPkts, but not - * - * Check the aComptRtcpPkt.problem , if the value is non-zero the packets - * should probably be discarded. - * - * @param rawPkt - * the byte array received from the socket - * @param packetSize - * the actual number of used bytes - * @param adr - * the socket address from which the packet was received - * @param rtpSession - * the RTPSession with the participant database - */ - - protected void init(byte[] rawPkt, int packetSize, InetSocketAddress adr, - RTPSession rtpSession) { - if (RTPSession.rtcpDebugLevel > 7) { - System.out.println("-> CompRtcpPkt(" + rawPkt.getClass() - + ", size " + packetSize + ", from " + adr.toString() - + ", " + rtpSession.getClass() + ")"); - } - // System.out.println("rawPkt.length:" + rawPkt.length + " packetSize:" - // + packetSize); - - // Chop it up - int start = 0; - - while (start < packetSize && problem == 0) { - int length = (StaticProcs.bytesToUIntInt(rawPkt, start + 2)) + 1; - - if (length * 4 + start > rawPkt.length) { - System.out.println("!!!! CompRtcpPkt.(rawPkt,..,..) length (" - + (length * 4 + start) - + ") exceeds size of raw packet (" + rawPkt.length - + ") !"); - this.problem = -3; - } - - int pktType = (int) rawPkt[start + 1]; - - if (pktType < 0) { - pktType += 256; - } - - if (start == 0) { - // Compound packets need to start with SR or RR - if (pktType != 200 && pktType != 201) { - if (RTPSession.rtcpDebugLevel > 3) { - System.out - .println("!!!! CompRtcpPkt(rawPkt...) packet did not start with SR or RR"); - } - this.problem = -1; - } - - // Padding bit should be zero for the first packet - if (((rawPkt[start] & 0x20) >>> 5) == 1) { - if (RTPSession.rtcpDebugLevel > 3) { - System.out - .println("!!!! CompRtcpPkt(rawPkt...) first packet was padded"); - } - this.problem = -2; - } - } - - // System.out.println("start: " + start + " pktType: " + pktType + - // " length:" + length ); - if (pktType == 200) { - addPacket(new RtcpPktSR(rawPkt, start, length * 4)); - } else if (pktType == 201) { - addPacket(new RtcpPktRR(rawPkt, start, -1)); - } else if (pktType == 202) { - addPacket(new RtcpPktSDES(rawPkt, start, adr, rtpSession.partDb)); - } else if (pktType == 203) { - addPacket(new RtcpPktBYE(rawPkt, start)); - } else if (pktType == 204) { - addPacket(new RtcpPktAPP(rawPkt, start)); - } else if (pktType == 205) { - addPacket(new RtcpPktRTPFB(rawPkt, start, rtpSession)); - } else if (pktType == 206) { - addPacket(new RtcpPktPSFB(rawPkt, start, rtpSession)); - } else { - System.out - .println("!!!! CompRtcpPkt(byte[] rawPkt, int packetSize...) " - + "UNKNOWN RTCP PACKET TYPE:" + pktType); - } - - // System.out.println(" start:" + start + " pktType:" + pktType + - // " length:" + length); - - start += length * 4; - - if (RTPSession.rtcpDebugLevel > 12) { - System.out.println(" start:" + start + " parsing pktType " - + pktType + " length: " + length); - } - } - if (RTPSession.rtcpDebugLevel > 7) { - System.out.println("<- CompRtcpPkt(rawPkt....)"); - } - } - - /** - * Encode combines the RTCP packets in this.rtcpPkts into a byte[] by - * calling the encode() function on each of them individually. - * - * The order of rtcpPkts is preserved, so a RR or SR packet must be first. - * - * @return the trimmed byte[] representation of the packet, ready to go into - * a UDP packet. - */ - protected byte[] encode() { - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" <- CompRtcpPkt.encode()"); - } - - ListIterator iter = rtcpPkts.listIterator(); - - byte[] rawPkt = new byte[1500]; - int index = 0; - - while (iter.hasNext()) { - RtcpPkt aPkt = (RtcpPkt) iter.next(); - - if (aPkt.packetType == 200) { - RtcpPktSR pkt = (RtcpPktSR) aPkt; - pkt.encode(); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else if (aPkt.packetType == 201) { - RtcpPktRR pkt = (RtcpPktRR) aPkt; - pkt.encode(); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else if (aPkt.packetType == 202) { - RtcpPktSDES pkt = (RtcpPktSDES) aPkt; - pkt.encode(); - // System.out.println(" ENCODE SIZE: " + pkt.rawPkt.length); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else if (aPkt.packetType == 203) { - RtcpPktBYE pkt = (RtcpPktBYE) aPkt; - pkt.encode(); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else if (aPkt.packetType == 204) { - RtcpPktAPP pkt = (RtcpPktAPP) aPkt; - pkt.encode(); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else if (aPkt.packetType == 205) { - RtcpPktRTPFB pkt = (RtcpPktRTPFB) aPkt; - pkt.encode(); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else if (aPkt.packetType == 206) { - RtcpPktPSFB pkt = (RtcpPktPSFB) aPkt; - pkt.encode(); - System.arraycopy(pkt.rawPkt, 0, rawPkt, index, - pkt.rawPkt.length); - index += pkt.rawPkt.length; - } else { - System.out.println("CompRtcpPkt aPkt.packetType:" - + aPkt.packetType); - } - // System.out.println(" packetType:" + aPkt.packetType + " length:" - // + aPkt.rawPkt.length + " index:" + index); - } - - byte[] output = new byte[index]; - - System.arraycopy(rawPkt, 0, output, 0, index); - - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" -> CompRtcpPkt.encode()"); - } - return output; - } -} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/DataFrame.java --- a/src/jlibrtp/DataFrame.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,295 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import org.sipdroid.net.tools.DatagramPool; -import org.sipdroid.net.tools.PktBufNodePool; -import org.sipdroid.net.tools.RtpPktPool; - -/** - * Data structure to hold a complete frame if frame reconstruction is enabled, - * or the data from an individual packet if it is not - * - * It also contains most of the data from the individual packets that it is - * based on. - * - * @author Arne Kepp - */ -public class DataFrame { - /** The share RTP timestamp */ - private long rtpTimestamp; - /** The calculated UNIX timestamp, guessed after 2 Sender Reports */ - private long timestamp = -1; - /** the SSRC from which this frame originated */ - private long SSRC; - /** contributing CSRCs, only read from the first packet */ - private long[] CSRCs; - /** RTP payload type */ - private int payloadType; - /** The marks on individual packets, ordered */ - //private boolean[] marks; - /** Whether any packets were marked or not */ - private boolean anyMarked = false; - /** Whether the frame contains the expected number of packets */ - private int isComplete = 0; - // private int dataLength; - /** The data from the individual packets, ordered */ - //private byte[][] data; - /** The sequence numbers of the individual packets, ordered */ - //private int[] seqNum; - /** The total amount of data bytes in this frame */ - private int totalLength = 0; - /** The last sequence number in this frame */ - protected int lastSeqNum; - /** The first sequence number in this frame */ - protected int firstSeqNum; - /** The number of packets expected for a complete frame */ - protected int noPkts; - private RtpPkt[] pkts = new RtpPkt[5]; - - /** - * The usual way to construct a frame is by giving it a PktBufNode, which - * contains links to all the other pkts that make it up. - */ - protected DataFrame(PktBufNode aBufNode, Participant p, int noPkts) { - initDataFrame(aBufNode, p, noPkts); - } - - protected void initDataFrame(PktBufNode aBufNode, Participant p, int noPkts) { - if (RTPSession.rtpDebugLevel > 6) { - System.out.println("-> DataFrame(PktBufNode, noPkts = " + noPkts - + ")"); - } - this.noPkts = noPkts; - RtpPkt aPkt = aBufNode.pkt; - int pktCount = aBufNode.pktCount; - firstSeqNum = aBufNode.pktCount; - PktBufNode tempNode; - - // All this data should be shared, so we just get it from the first one - this.rtpTimestamp = aBufNode.timeStamp; - SSRC = aPkt.getSsrc(); - CSRCs = aPkt.getCsrcArray(); - - // Check whether we can compute an NTPish timestamp? Requires two SR - // reports - if (p.ntpGradient > 0) { - // System.out.print(Long.toString(p.ntpOffset)+" " - timestamp = p.ntpOffset - + (long) (p.ntpGradient * (double) (this.rtpTimestamp - p.lastSRRtpTs)); - } - - // Make data the right length - int payloadLength = aPkt.getPayloadLength(); - //seqNum = new int[aBufNode.pktCount]; - //marks = new boolean[aBufNode.pktCount]; - if (pktCount > 5) { - System.out.println("PKT COUNT TOO HIGH " + pktCount); - } - // Concatenate the data of the packets - int i; - for (i = 0; i < pktCount; i++) { - aPkt = aBufNode.pkt; - pkts[i] = aPkt; - // System.out.println("i " + i + " seqNum[i] " + seqNum[i] + - // " aBufNode" + aBufNode); - //seqNum[i] = aBufNode.seqNum; - if (aBufNode.pkt.isMarked()) - anyMarked = true; - - // Get next node - tempNode = aBufNode; - aBufNode = aBufNode.nextFrameNode; - PktBufNodePool.getInstance().returnBufNode(tempNode); - lastSeqNum = aPkt.getSeqNumber(); - } - - if (noPkts > 0) { - int seqDiff = firstSeqNum - lastSeqNum; - if (seqDiff < 0) - seqDiff = (Integer.MAX_VALUE - firstSeqNum) + lastSeqNum; - if (seqDiff == pktCount && pktCount == noPkts) - isComplete = 1; - } else { - isComplete = -1; - } - - if (RTPSession.rtpDebugLevel > 6) { - System.out.println("<- DataFrame(PktBufNode, noPkt), data length: " - + pkts.length); - } - } - - public DataFrame(){ - } - - /** - * Returns a two dimensial array where the first dimension represents - * individual packets, from which the frame is made up, in order of - * increasing sequence number. These indeces can be matched to the sequence - * numbers returned by sequenceNumbers(). - * - * @return 2-dim array with raw data from packets - */ - /*public byte[][] getData() { - return this.data; - }*/ - - public RtpPkt[] getPkt(){ - return this.pkts ; - } - - /** - * Returns a concatenated version of the data from getData() It ignores - * missing sequence numbers, but then isComplete() will return false - * provided that RTPAppIntf.frameSize() provides a non-negative number for - * this payload type. - * - * @return byte[] with all the data concatenated - */ - /*public byte[] getConcatenatedData() { - if (this.noPkts < 2) { - byte[] ret = new byte[this.totalLength]; - int pos = 0; - - for (int i = 0; i < data.length; i++) { - int length = data[i].length; - - // Last packet may be shorter - if (pos + length > totalLength) - length = totalLength - pos; - - System.arraycopy(data[i], 0, ret, pos, length); - pos += data[i].length; - } - return ret; - } else { - return data[0]; - } - }*/ - - /** - * If two SR packet have been received jlibrtp will attempt to calculate the - * local UNIX timestamp (in milliseconds) of all packets received. - * - * This value should ideally correspond to the local time when the SSRC sent - * the packet. Note that the source may not be reliable. - * - * Returns -1 if less than two SRs have been received - * - * @return the UNIX timestamp, similar to System.currentTimeMillis() or -1; - */ - public long timestamp() { - return this.timestamp; - - } - - /** - * Returns the RTP timestamp of all the packets in the frame. - * - * @return unmodified RTP timestamp - */ - public long rtpTimestamp() { - return this.rtpTimestamp; - } - - /** - * Returns the payload type of the packets - * - * @return the payload type of the packets - */ - public int payloadType() { - return this.payloadType; - } - - /** - * Returns an array whose values, for the same index, correpond to the - * sequence number of the packet from which the data came. - * - * This information can be valuable in conjunction with getData(), to - * identify what parts of a frame are missing. - * - * @return array with sequence numbers - */ - /*public int[] sequenceNumbers() { - return seqNum; - }*/ - - /** - * Returns an array whose values, for the same index, correpond to whether - * the data was marked or not. - * - * This information can be valuable in conjunction with getData(). - * - * @return array of booleans - */ - /*public boolean[] marks() { - return this.marks; - }*/ - - /** - * Returns true if any packet in the frame was marked. - * - * This function should be used if all your frames fit into single packets. - * - * @return true if any packet was marked, false otherwise - */ - public boolean marked() { - return this.anyMarked; - } - - /** - * The SSRC associated with this frame. - * - * @return the ssrc that created this frame - */ - public long ssrc() { - return this.SSRC; - } - - /** - * The SSRCs that contributed to this frame - * - * @return an array of contributing SSRCs, or null - */ - public long[] csrcs() { - return this.CSRCs; - } - - /** - * Checks whether the difference in sequence numbers corresponds to the - * number of packets received for the current timestamp, and whether this - * value corresponds to the expected number of packets. - * - * @return true if the right number of packets make up the frame - */ - public int complete() { - return this.isComplete; - } - - public void release() { - for(RtpPkt pkt : this.pkts) { - if (pkt != null) { - if (pkt.getDatagramPacket() != null) - DatagramPool.getInstance().returnPacket(pkt.getDatagramPacket()); - RtpPktPool.getInstance().returnPkt(pkt); - } - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/DebugAppIntf.java --- a/src/jlibrtp/DebugAppIntf.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.InetSocketAddress; - -/** - * DebugAppIntf can be registered on RTPSession to provide simple debugging - * functionality. This is particularly useful to determine whether the client is - * receing any data at all. - * - * @author Arne Kepp - * - */ - -public interface DebugAppIntf { - /** - * This function wil notify you of any packets received, valid or not. - * Useful for network debugging, and finding bugs in jlibrtp. - * - * Type is an integer describing the type of event -2 - Invalid RTCP packet - * received -1 - Invalid RTP packet received 0 - RTP packet received 1 - - * RTCP packet received - * - * Description is a string that should be meaningful to advanced users, such - * as"RTP packet received from 127.0.0.1:12312, SSRC: 1380912 , payload type 1, packet size 16 octets" - * or "Invalid RTP packet received from 127.0.0.1:12312" - * - * This function is synchonous and should return quickly. - * - * @param type - * , the type of event, see above. - * @param socket - * , taken directly from the UDP packet - * @param description - * , see above. - */ - public void packetReceived(int type, InetSocketAddress socket, - String description); - - /** - * This function will notify you of any packets sent from this instance of - * RTPSession. Useful for network debugging, and finding bugs in jlibrtp. - * - * Type is an integer describing the type of event 0 - RTP unicast packet - * sent 1 - RTP multicast packet sent 2 - RTCP unicast packet sent 3 - RTCP - * multicast packet sent - * - * Description is a string that should be meaningful to advanced users, such - * as - * - * This function is synchonous and should return quickly. - * - * @param type - * , the type of event, see above - * @param socket - * , taken directly from the UDP packet - * @param description - * , see above - */ - public void packetSent(int type, InetSocketAddress socket, - String description); - - /** - * Other important events that can occur in session -1 SSRC conflict 0 - * Session is terminating - * - * @param type - * see above - * @param description - * , see above - */ - public void importantEvent(int type, String description); -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/LICENSE.txt --- a/src/jlibrtp/LICENSE.txt Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,490 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/Participant.java --- a/src/jlibrtp/Participant.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,464 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.InetSocketAddress; - -/** - * A participant represents a peer in an RTPSession. Based on the information - * stored on these objects, packets are processed and statistics generated for - * RTCP. - */ -public class Participant { - /** - * Whether the participant is unexpected, e.g. arrived through unicast with - * SDES - */ - protected boolean unexpected = false; - /** Where to send RTP packets (unicast) */ - protected InetSocketAddress rtpAddress = null; - /** Where to send RTCP packets (unicast) */ - protected InetSocketAddress rtcpAddress = null; - /** Where the first RTP packet was received from */ - protected InetSocketAddress rtpReceivedFromAddress = null; - /** Where the first RTCP packet was received from */ - protected InetSocketAddress rtcpReceivedFromAddress = null; - - /** SSRC of participant */ - protected long ssrc = -1; - /** SDES CNAME */ - protected String cname = null; - /** SDES The participant's real name */ - protected String name = null; - /** SDES The participant's email */ - protected String email = null; - /** SDES The participant's phone number */ - protected String phone = null; - /** SDES The participant's location */ - protected String loc = null; - /** SDES The tool the participants is using */ - protected String tool = null; - /** SDES A note */ - protected String note = null; - /** SDES A priv string, loosely defined */ - protected String priv = null; - - // Receiver Report Items - /** RR First sequence number */ - protected int firstSeqNumber = -1; - /** RR Last sequence number */ - protected int lastSeqNumber = 0; - /** RR Number of times sequence number has rolled over */ - protected long seqRollOverCount = 0; - /** RR Number of packets received */ - protected long receivedPkts = 0; - /** RR Number of octets received */ - protected long receivedOctets = 0; - /** RR Number of packets received since last SR */ - protected int receivedSinceLastSR = 0; - /** RR Sequence number associated with last SR */ - protected int lastSRRseqNumber = 0; - /** RR Interarrival jitter */ - protected double interArrivalJitter = -1.0; - /** RR Last received RTP Timestamp */ - protected long lastRtpTimestamp = 0; - - /** RR Middle 32 bits of the NTP timestamp in the last SR */ - protected long timeStampLSR = 0; - /** RR The time when we actually got the last SR */ - protected long timeReceivedLSR = 0; - - /** Gradient where UNIX timestamp = ntpGradient*RTPTimestamp * ntpOffset */ - protected double ntpGradient = -1; - /** Offset where UNIX timestamp = ntpGradient*RTPTimestamp * ntpOffset */ - protected long ntpOffset = -1; - /** Last NTP received in SR packet, MSB */ - protected long lastNtpTs1 = 0; // 32 bits - /** Last NTP received in SR packet, LSB */ - protected long lastNtpTs2 = 0; // 32 bits - /** RTP Timestamp in last SR packet */ - protected long lastSRRtpTs = 0; // 32 bits - - /** UNIX time when a BYE was received from this participant, for pruning */ - protected long timestampBYE = -1; // The user said BYE at this time - - /** Store the packets received from this participant */ - protected PktBuffer pktBuffer = null; - - /** - * UNIX time of last RTP packet, to check whether this participant has sent - * anything recently - */ - protected long lastRtpPkt = -1; // Time of last RTP packet - /** - * UNIX time of last RTCP packet, to check whether this participant has sent - * anything recently - */ - protected long lastRtcpPkt = -1; // Time of last RTCP packet - /** - * UNIX time this participant was added by application, to check whether we - * ever heard back - */ - protected long addedByApp = -1; // Time the participant was added by - // application - /** UNIX time of last time we sent an RR to this user */ - protected long lastRtcpRRPkt = -1; // Timestamp of last time we sent this - // person an RR packet - /** Unix time of second to last time we sent and RR to this user */ - protected long secondLastRtcpRRPkt = -1; // Timestamp of 2nd to last time we - // sent this person an RR Packet - - /** - * Create a basic participant. If this is a unicast session you must - * provide network address (ipv4 or ipv6) and ports for RTP and RTCP, as - * well as a cname for this contact. These things should be negotiated - * through SIP or a similar protocol. - * - * jlibrtp will listen for RTCP packets to obtain a matching SSRC for this - * participant, based on cname. - * - * @param networkAddress - * string representation of network address (ipv4 or ipv6). Use - * "127.0.0.1" for multicast session. - * @param rtpPort - * port on which peer expects RTP packets. Use 0 if this is a - * sender-only, or this is a multicast session. - * @param rtcpPort - * port on which peer expects RTCP packets. Use 0 if this is a - * sender-only, or this is a multicast session. - */ - public Participant(String networkAddress, int rtpPort, int rtcpPort) { - if (RTPSession.rtpDebugLevel > 6) { - System.out.println("Creating new participant: " + networkAddress); - } - - // RTP - if (rtpPort > 0) { - try { - rtpAddress = new InetSocketAddress(networkAddress, rtpPort); - } catch (Exception e) { - System.out.println("Couldn't resolve " + networkAddress); - } - // isReceiver = true; - } - - // RTCP - if (rtcpPort > 0) { - try { - rtcpAddress = new InetSocketAddress(networkAddress, rtcpPort); - } catch (Exception e) { - System.out.println("Couldn't resolve " + networkAddress); - } - } - - // By default this is a sender - // isSender = true; - } - - // We got a packet, but we don't know this person yet. - protected Participant(InetSocketAddress rtpAdr, InetSocketAddress rtcpAdr, - long SSRC) { - rtpReceivedFromAddress = rtpAdr; - rtcpReceivedFromAddress = rtcpAdr; - ssrc = SSRC; - unexpected = true; - } - - // Dummy constructor to ease testing - protected Participant() { - System.out.println("Don't use the Participan(void) Constructor!"); - } - - /** - * RTP Address registered with this participant. - * - * @return address of participant - */ - InetSocketAddress getRtpSocketAddress() { - return rtpAddress; - } - - /** - * RTCP Address registered with this participant. - * - * @return address of participant - */ - InetSocketAddress getRtcpSocketAddress() { - return rtcpAddress; - } - - /** - * InetSocketAddress this participant has used to send us RTP packets. - * - * @return address of participant - */ - InetSocketAddress getRtpReceivedFromAddress() { - return rtpAddress; - } - - /** - * InetSocketAddress this participant has used to send us RTCP packets. - * - * @return address of participant - */ - InetSocketAddress getRtcpReceivedFromAddress() { - return rtcpAddress; - } - - /** - * CNAME registered for this participant. - * - * @return the cname - */ - public String getCNAME() { - return cname; - } - - /** - * NAME registered for this participant. - * - * @return the name - */ - public String getNAME() { - return name; - } - - /** - * EMAIL registered for this participant. - * - * @return the email address - */ - public String getEmail() { - return email; - } - - /** - * PHONE registered for this participant. - * - * @return the phone number - */ - public String getPhone() { - return phone; - } - - /** - * LOCATION registered for this participant. - * - * @return the location - */ - public String getLocation() { - return loc; - } - - /** - * NOTE registered for this participant. - * - * @return the note - */ - public String getNote() { - return note; - } - - /** - * PRIVATE something registered for this participant. - * - * @return the private-string - */ - public String getPriv() { - return priv; - } - - /** - * TOOL something registered for this participant. - * - * @return the tool - */ - public String getTool() { - return tool; - } - - /** - * SSRC for participant, determined through RTCP SDES - * - * @return SSRC (32 bit unsigned integer as long) - */ - public long getSSRC() { - return this.ssrc; - } - - /** - * Updates the participant with information for receiver reports. - * - * @param packetLength - * to keep track of received octets - * @param pkt - * the most recently received packet - */ - protected void updateRRStats(int packetLength, RtpPkt pkt) { - int curSeqNum = pkt.getSeqNumber(); - - if (firstSeqNumber < 0) { - firstSeqNumber = curSeqNum; - } - - receivedOctets += packetLength; - receivedSinceLastSR++; - receivedPkts++; - - long curTime = System.currentTimeMillis(); - - if (this.lastSeqNumber < curSeqNum) { - // In-line packet, best thing you could hope for - this.lastSeqNumber = curSeqNum; - - } else if (this.lastSeqNumber - this.lastSeqNumber < -100) { - // Sequence counter rolled over - this.lastSeqNumber = curSeqNum; - seqRollOverCount++; - - } else { - // This was probably a duplicate or a late arrival. - } - - // Calculate jitter - if (this.lastRtpPkt > 0) { - - long D = (pkt.getTimeStamp() - curTime) - - (this.lastRtpTimestamp - this.lastRtpPkt); - if (D < 0) - D = (-1) * D; - - this.interArrivalJitter += ((double) D - this.interArrivalJitter) / 16.0; - } - - lastRtpPkt = curTime; - lastRtpTimestamp = pkt.getTimeStamp(); - } - - /** - * Calculates the extended highest sequence received by adding the last - * sequence number to 65536 times the number of times the sequence counter - * has rolled over. - * - * @return extended highest sequence - */ - protected long getExtHighSeqRecv() { - return (65536 * seqRollOverCount + lastSeqNumber); - } - - /** - * Get the fraction of lost packets, calculated as described in RFC 3550 as - * a fraction of 256. - * - * @return the fraction of lost packets since last SR received - */ - protected int getFractionLost() { - int expected = (lastSeqNumber - lastSRRseqNumber); - if (expected < 0) - expected = 65536 + expected; - - int fraction = 256 * (expected - receivedSinceLastSR); - if (expected > 0) { - fraction = (fraction / expected); - } else { - fraction = 0; - } - - // Clear counters - receivedSinceLastSR = 0; - lastSRRseqNumber = lastSeqNumber; - - return fraction; - } - - /** - * The total number of packets lost during the session. - * - * Returns zero if loss is negative, i.e. duplicates have been received. - * - * @return number of lost packets, or zero. - */ - protected long getLostPktCount() { - long lost = (this.getExtHighSeqRecv() - this.firstSeqNumber) - - receivedPkts; - - if (lost < 0) - lost = 0; - return lost; - } - - /** - * - * @return the interArrivalJitter, calculated continuously - */ - protected double getInterArrivalJitter() { - return this.interArrivalJitter; - } - - /** - * Set the timestamp for last sender report - * - * @param ntp1 - * high order bits - * @param ntp2 - * low order bits - */ - protected void setTimeStampLSR(long ntp1, long ntp2) { - // Use what we've got - byte[] high = StaticProcs.uIntLongToByteWord(ntp1); - byte[] low = StaticProcs.uIntLongToByteWord(ntp2); - low[3] = low[1]; - low[2] = low[0]; - low[1] = high[3]; - low[0] = high[2]; - - this.timeStampLSR = StaticProcs.bytesToUIntLong(low, 0); - } - - /** - * Calculate the delay between the last received sender report and now. - * - * @return the delay in units of 1/65.536ms - */ - protected long delaySinceLastSR() { - if (this.timeReceivedLSR < 1) - return 0; - - long delay = System.currentTimeMillis() - this.timeReceivedLSR; - - // Convert ms into 1/65536s = 1/65.536ms - return (long) ((double) delay * 65.536); - } - - /** - * Only for debugging purposes - */ - public void debugPrint() { - System.out.print(" Participant.debugPrint() SSRC:" + this.ssrc - + " CNAME:" + this.cname); - if (this.rtpAddress != null) - System.out.print(" RTP:" + this.rtpAddress.toString()); - if (this.rtcpAddress != null) - System.out.print(" RTCP:" + this.rtcpAddress.toString()); - System.out.println(""); - - System.out.println(" Packets received:" - + this.receivedPkts); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/ParticipantDatabase.java --- a/src/jlibrtp/ParticipantDatabase.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.concurrent.ConcurrentHashMap; - -/** - * The participant database maintains three hashtables with participants. - * - * The key issue is to be fast for operations that happen every time an RTP - * packet is sent or received. We allow linear searching in cases where we need - * to update participants with information. - * - * The keying is therefore usually the SSRC. In cases where we have the cname, - * but no SSRC is known (no SDES packet has been received), a simple hash i - * calculated based on the CNAME. The RTCP code should, when receiving SDES - * packets, check whether the participant is known and update the copy in this - * database with SSRC if needed. - * - * @author Arne Kepp - */ -public class ParticipantDatabase { - /** The parent RTP Session */ - RTPSession rtpSession = null; - /** - * A linked list to hold participants explicitly added by the application In - * unicast mode this is the list used for RTP and RTCP transmission, in - * multicast it should not be in use. - */ - LinkedList receivers = new LinkedList(); - /** - * The hashtable holds participants added through received RTP and RTCP - * packets, as well as participants that have been linked to an SSRC by ip - * address (in unicast mode). - */ - ConcurrentHashMap ssrcTable = new ConcurrentHashMap(); - - /** - * Simple constructor - * - * @param parent - * parent RTPSession - */ - protected ParticipantDatabase(RTPSession parent) { - rtpSession = parent; - } - - /** - * - * @param cameFrom - * 0: Application, 1: RTP packet, 2: RTCP - * @param p - * the participant - * @return 0 if okay, -1 if not - */ - protected int addParticipant(int cameFrom, Participant p) { - // Multicast or not? - if (this.rtpSession.mcSession) { - return this.addParticipantMulticast(cameFrom, p); - } else { - return this.addParticipantUnicast(cameFrom, p); - } - - } - - /** - * Add a multicast participant to the database - * - * @param cameFrom - * 0: Application, 1,2: discovered through RTP or RTCP - * @param p - * the participant to add - * @return 0 if okay, -2 if redundant, -1 if adding participant to multicast - */ - private int addParticipantMulticast(int cameFrom, Participant p) { - if (cameFrom == 0) { - System.out - .println("ParticipantDatabase.addParticipant() doesnt expect" - + " application to add participants to multicast session."); - return -1; - } else { - // Check this one is not redundant - if (this.ssrcTable.contains(p.ssrc)) { - System.out.println("ParticipantDatabase.addParticipant() SSRC " - + "already known " + Long.toString(p.ssrc)); - return -2; - } else { - this.ssrcTable.put(p.ssrc, p); - return 0; - } - } - } - - /** - * Add a unicast participant to the database - * - * Result will be reported back through tpSession.appIntf.userEvent - * - * @param cameFrom - * 0: Application, 1,2: discovered through RTP or RTCP - * @param p - * the participant to add - * @return 0 if new, 1 if - */ - private int addParticipantUnicast(int cameFrom, Participant p) { - if (cameFrom == 0) { - // Check whether there is a match in the ssrcTable - boolean notDone = true; - - Enumeration enu = this.ssrcTable.elements(); - while (notDone && enu.hasMoreElements()) { - Participant part = enu.nextElement(); - if (part.unexpected - && (part.rtcpReceivedFromAddress - .equals(part.rtcpAddress.getAddress()) || part.rtpReceivedFromAddress - .equals(part.rtpAddress.getAddress()))) { - - part.rtpAddress = p.rtpAddress; - part.rtcpAddress = p.rtcpAddress; - part.unexpected = false; - - // Report the match back to the application - Participant[] partArray = { part }; - this.rtpSession.appIntf.userEvent(5, partArray); - - notDone = false; - p = part; - } - } - - // Add to the table of people that we send packets to - this.receivers.add(p); - return 0; - - } else { - // Check whether there's a match in the receivers table - boolean notDone = true; - // System.out.println("GOT " + p.cname); - Iterator iter = this.receivers.iterator(); - - while (notDone && iter.hasNext()) { - Participant part = iter.next(); - - // System.out.println(part.rtpAddress.getAddress().toString() - // + " " + part.rtcpAddress.getAddress().toString() - // + " " + p.rtpReceivedFromAddress.getAddress().toString() - // + " " + p.rtcpReceivedFromAddress.getAddress().toString()); - - // System.out.println(" HUUHHHH? " + - // p.rtcpReceivedFromAddress.getAddress().equals(part.rtcpAddress.getAddress())); - if ((cameFrom == 1 && p.rtpReceivedFromAddress.getAddress() - .equals(part.rtpAddress.getAddress())) - || (cameFrom == 2 && p.rtcpReceivedFromAddress - .getAddress().equals( - part.rtcpAddress.getAddress()))) { - - part.rtpReceivedFromAddress = p.rtpReceivedFromAddress; - part.rtcpReceivedFromAddress = p.rtcpReceivedFromAddress; - - // Move information - part.ssrc = p.ssrc; - part.cname = p.cname; - part.name = p.name; - part.loc = p.loc; - part.phone = p.phone; - part.email = p.email; - part.note = p.note; - part.tool = p.tool; - part.priv = p.priv; - - this.ssrcTable.put(part.ssrc, part); - - // Report the match back to the application - Participant[] partArray = { part }; - this.rtpSession.appIntf.userEvent(5, partArray); - return 0; - } - } - - // No match? ok - this.ssrcTable.put(p.ssrc, p); - return 0; - } - } - - /** - * Remove a participant from all tables - * - * @param p - * the participant to be removed - */ - protected void removeParticipant(Participant p) { - if (!this.rtpSession.mcSession) - this.receivers.remove(p); - - this.ssrcTable.remove(p.ssrc, p); - } - - /** - * Find a participant based on the ssrc - * - * @param ssrc - * of the participant to be found - * @return the participant, null if unknonw - */ - protected Participant getParticipant(long ssrc) { - Participant p = null; - p = ssrcTable.get(ssrc); - return p; - } - - /** - * Iterator for all the unicast receivers. - * - * This one is used by both RTP for sending packets, as well as RTCP. - * - * @return iterator for unicast participants - */ - protected Iterator getUnicastReceivers() { - if (!this.rtpSession.mcSession) { - return this.receivers.iterator(); - } else { - System.out - .println("Request for ParticipantDatabase.getUnicastReceivers in multicast session"); - return null; - } - } - - /** - * Enumeration of all the participants with known ssrcs. - * - * This is primarily used for sending packets in multicast sessions. - * - * @return enumerator with all the participants with known SSRCs - */ - protected Enumeration getParticipants() { - return this.ssrcTable.elements(); - } - - protected void debugPrint() { - System.out.println(" ParticipantDatabase.debugPrint()"); - Participant p; - Enumeration enu = ssrcTable.elements(); - while (enu.hasMoreElements()) { - p = (Participant) enu.nextElement(); - System.out.println(" ssrcTable ssrc:" + p.ssrc - + " cname:" + p.cname + " loc:" + p.loc + " rtpAddress:" - + p.rtpAddress + " rtcpAddress:" + p.rtcpAddress); - } - - Iterator iter = receivers.iterator(); - while (iter.hasNext()) { - p = iter.next(); - System.out.println(" receivers: " - + p.rtpAddress.toString()); - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/PktBufNode.java --- a/src/jlibrtp/PktBufNode.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * This is a four-directional data structures used for the frame buffer, i.e. - * buffer for pkts that need to be assimilated into complete frames. - * - * All the actual work is done by PktBuffer. - * - * @author Arne Kepp - * - */ -public class PktBufNode { - /** The next node (RTP Timestamp), looking from the back -> next means older */ - protected PktBufNode nextFrameQueueNode = null; - /** - * The previous node (RTP Timestmap), looking from the back -> prev means - * newer - */ - protected PktBufNode prevFrameQueueNode = null; - /** - * The next node within the frame, i.e. higher sequence number, same RTP - * timestamp - */ - protected PktBufNode nextFrameNode = null; - /** Number of packets with the same RTP timestamp */ - protected int pktCount; - /** The RTP timeStamp associated with this node */ - protected long timeStamp; - /** The sequence number associated with this node */ - protected int seqNum; - /** The payload, a parsed RTP Packet */ - protected RtpPkt pkt = null; - - /** - * Create a new packet buffer node based on a packet - * - * @param aPkt - * the packet - */ - protected PktBufNode(RtpPkt aPkt) { - initPktBufNode(aPkt); - } - - public PktBufNode(){ - } - - public void initPktBufNode(RtpPkt aPkt) { - pkt = aPkt; - timeStamp = aPkt.getTimeStamp(); - seqNum = aPkt.getSeqNumber(); - pktCount = 1; - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/PktBuffer.java --- a/src/jlibrtp/PktBuffer.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,533 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import org.sipdroid.net.tools.DataFramePool; -import org.sipdroid.net.tools.PktBufNodePool; - -/** - * A PktBuffer stores packets either for buffering purposes, or because they - * need to be assimilated to create a complete frame. - * - * This behavior can be controlled through rtpSession.pktBufBehavior() - * - * It optionally drops duplicate packets. - * - * Note that newest is the most recently received, i.e. highest timeStamp Next - * means new to old (from recently received to previously received) - * - * @author Arne Kepp - */ -public class PktBuffer { - /** - * The RTPSession holds information common to all packetBuffers, such as max - * size - */ - RTPSession rtpSession; - /** SSRC of the the participant that this buffer is for */ - long SSRC; - /** The parent participant */ - Participant p; - /** The length of the buffer */ - int length = 0; - /** The oldest, least recently received, packet */ - PktBufNode oldest = null; - /** The newest, most recently received, packet */ - PktBufNode newest = null; - - /** The last sequence number received */ - int lastSeqNumber = -1; - /** The last timestamp */ - long lastTimestamp = -1; - - /** - * Creates a new PktBuffer, a linked list of PktBufNode - * - * @param rtpSession - * the parent RTPSession - * @param p - * the participant to which this packetbuffer belongs. - * @param aPkt - * The first RTP packet, to be added to the buffer - */ - protected PktBuffer(RTPSession rtpSession, Participant p, RtpPkt aPkt) { - this.rtpSession = rtpSession; - this.p = p; - SSRC = aPkt.getSsrc(); - PktBufNode newNode = PktBufNodePool.getInstance().borrowBufNode(); - newNode.initPktBufNode(aPkt); - oldest = newNode; - newest = newNode; - // lastSeqNumber = (aPkt.getSeqNumber() - 1); - // lastTimestamp = aPkt.getTimeStamp(); - length = 1; - } - - /** - * Adds a packet, this happens in constant time if they arrive in order. - * Optimized for the case where each pkt is a complete frame. - * - * @param aPkt - * the packet to be added to the buffer. - * @return integer, negative if operation failed (see code) - */ - protected synchronized int addPkt(RtpPkt aPkt) { - if (aPkt == null) { - System.out.println("! PktBuffer.addPkt(aPkt) aPkt was null"); - return -5; - } - - long timeStamp = aPkt.getTimeStamp(); - if (RTPSession.rtpDebugLevel > 7) { - System.out.println("-> PktBuffer.addPkt() , length:" + length - + " , timeStamp of Pkt: " + Long.toString(timeStamp)); - } - - PktBufNode newNode = PktBufNodePool.getInstance().borrowBufNode(); - newNode.initPktBufNode(aPkt); - if (aPkt.getSsrc() != SSRC) { - System.out.println("PktBuffer.addPkt() SSRCs don't match!"); - } - - int retVal = 0; - if (this.rtpSession.pktBufBehavior > 0) { - retVal = bufferedAddPkt(newNode); - } else if (this.rtpSession.pktBufBehavior == 0) { - retVal = filteredAddPkt(newNode); - } else if (this.rtpSession.pktBufBehavior == -1) { - retVal = unfilteredAddPkt(newNode); - } - - if (RTPSession.rtpDebugLevel > 7) { - if (RTPSession.rtpDebugLevel > 10) { - this.debugPrint(); - } - System.out.println("<- PktBuffer.addPkt() , length:" + length - + " returning " + retVal); - } - return retVal; - } - - /** - * Adds packets in the same order that they arrive, doesn't do any filering - * or processing. - * - * @param newNode - * the node to add to the packet buffer - * @return 0 if everything is okay, -1 otherwise - */ - private int unfilteredAddPkt(PktBufNode newNode) { - if (RTPSession.rtpDebugLevel > 8) { - System.out.println("<-> PktBuffer.unfilteredAddPkt()"); - } - // No magic, just add to the end - if (oldest != null) { - oldest.nextFrameQueueNode = newNode; - newNode.prevFrameQueueNode = oldest; - oldest = newNode; - } else { - oldest = newNode; - newest = newNode; - } - return 0; - } - - /** - * Takes care of duplicate packets - * - * @param newNode - * the node to add to the packet buffer - * @return 0 if everything is okay, -1 otherwise - */ - private int filteredAddPkt(PktBufNode newNode) { - if (RTPSession.rtpDebugLevel > 8) { - System.out.println("<-> PktBuffer.filteredAddPkt()"); - } - - if (length == 0) { - // The buffer was empty, this packet is the one and only. - newest = newNode; - oldest = newNode; - length = 1; - } else { - // The packetbuffer is not empty. - if (newNode.timeStamp > newest.timeStamp - || newNode.seqNum > newest.seqNum - && (newNode.seqNum - newest.seqNum) < 10) { - // Packet came in order - newNode.nextFrameQueueNode = newest; - newest.prevFrameQueueNode = newNode; - newest = newNode; - length++; - } else { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println("PktBuffer.filteredAddPkt Dropped a packet due to lag! " - + newNode.timeStamp - + " " - + newNode.seqNum - + " vs " - + oldest.timeStamp - + " " - + oldest.seqNum); - } - return -1; - } - } - - return 0; - } - - /** - * Does most of the packet organization for the application. Packets are put - * in order, duplicate packets or late arrivals are discarded - * - * If multiple packets make up a frame, these will also be organized by RTP - * timestamp and sequence number, and returned as a complete frame. - * - * @param newNode - * the node to add to the packet buffer - * @return 0 if everything is okay, -1 otherwise - */ - private int bufferedAddPkt(PktBufNode newNode) { - if (RTPSession.rtpDebugLevel > 8) { - System.out.println("<-> PktBuffer.bufferedAddPkt()"); - } - if (length == 0) { - // The buffer was empty, this packet is the one and only. - newest = newNode; - oldest = newNode; - } else { - // The packetbuffer is not empty. - if (newNode.timeStamp > newest.timeStamp - || newNode.seqNum > newest.seqNum) { - // Packet came in order - newNode.nextFrameQueueNode = newest; - newest.prevFrameQueueNode = newNode; - newest = newNode; - } else { - // There are packets, we need to order this one right. - if (!pktOnTime(newNode.timeStamp, newNode.seqNum) - && rtpSession.pktBufBehavior > -1) { - // We got this too late, can't put it in order anymore. - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println("PktBuffer.addPkt Dropped a packet due to lag! " - + newNode.timeStamp - + " " - + newNode.seqNum - + " vs " - + oldest.timeStamp - + " " - + oldest.seqNum); - } - return -1; - } - - // Need to do some real work, find out where it belongs (linear - // search from the back). - PktBufNode tmpNode = newest; - while (tmpNode.timeStamp > newNode.timeStamp) { - tmpNode = tmpNode.nextFrameQueueNode; - } - - if (tmpNode.timeStamp == newNode.timeStamp - && rtpSession.frameReconstruction - && newNode.seqNum != tmpNode.seqNum) { - // Packet has same timestamp, presumably belongs to frame. - // Need to order within frame. - if (RTPSession.rtpDebugLevel > 8) { - System.out - .println("Found pkt with existing timeStamp: " - + newNode.timeStamp); - } - int ret = addToFrame(tmpNode, newNode); - if (ret != 0) { - return ret; - } - } else { - - // Check that it's not a duplicate - if (tmpNode.timeStamp == newNode.timeStamp - && newNode.seqNum == tmpNode.seqNum) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println("PktBuffer.addPkt Dropped a duplicate packet! " - + newNode.timeStamp - + " " - + newNode.seqNum); - } - return -1; - } - - // Insert into buffer - newNode.nextFrameQueueNode = tmpNode; - newNode.prevFrameQueueNode = tmpNode.prevFrameQueueNode; - - // Update the node behind - if (newNode.prevFrameQueueNode != null) { - newNode.prevFrameQueueNode.nextFrameQueueNode = newNode; - } - tmpNode.prevFrameQueueNode = newNode; - - if (newNode.timeStamp > newest.timeStamp) { - newest = newNode; - } - } - } - } - // Update the length of this buffer - length++; - return 0; - } - - /** - * - * @param frameNode - * the node currently representing the frame in the packet buffer - * @param newNode - * the new node to be added to the frame - * @return 0 if no error, -2 if this is a duplicate packet - */ - private int addToFrame(PktBufNode frameNode, PktBufNode newNode) { - // Node has same timeStamp, assume pkt belongs to frame - - if (frameNode.seqNum < newNode.seqNum) { - // this is not the first packet in the frame - frameNode.pktCount++; - - // Find the right spot - while (frameNode.nextFrameNode != null - && frameNode.nextFrameNode.seqNum < newNode.seqNum) { - frameNode = frameNode.nextFrameNode; - } - - // Check whether packet is duplicate - if (frameNode.nextFrameNode != null - && frameNode.nextFrameNode.seqNum == newNode.seqNum) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println("PktBuffer.addPkt Dropped a duplicate packet!"); - } - return -2; - } - - newNode.nextFrameNode = frameNode.nextFrameNode; - frameNode.nextFrameNode = newNode; - - } else { - // newNode has the lowest sequence number - newNode.nextFrameNode = frameNode; - newNode.pktCount = frameNode.pktCount + 1; - - // Update the queue - if (frameNode.nextFrameQueueNode != null) { - frameNode.nextFrameQueueNode.prevFrameQueueNode = newNode; - newNode.nextFrameQueueNode = frameNode.nextFrameQueueNode; - frameNode.nextFrameQueueNode = null; - } - if (frameNode.prevFrameQueueNode != null) { - frameNode.prevFrameQueueNode.nextFrameQueueNode = newNode; - newNode.prevFrameQueueNode = frameNode.prevFrameQueueNode; - frameNode.prevFrameQueueNode = null; - } - if (newest.timeStamp == newNode.timeStamp) { - newest = newNode; - } - } - - return 0; - } - - /** - * Checks the oldest frame, if there is one, sees whether it is complete. - * - * @return Returns null if there are no complete frames available. - */ - protected synchronized DataFrame popOldestFrame() { - if (RTPSession.rtpDebugLevel > 7) { - System.out.println("-> PktBuffer.popOldestFrame()"); - } - if (RTPSession.rtpDebugLevel > 10) { - this.debugPrint(); - } - - if (this.rtpSession.pktBufBehavior > 0) { - return this.bufferedPopFrame(); - } else { - return this.unbufferedPopFrame(); - } - } - - /** - * Will return the oldest frame without checking whether it is in the right - * order, or whether we should wate for late arrivals. - * - * @return the first frame on the queue, null otherwise - */ - private DataFrame unbufferedPopFrame() { - if (oldest != null) { - PktBufNode retNode = oldest; - - popFrameQueueCleanup(retNode, retNode.seqNum); - DataFrame df = DataFramePool.getInstance().borrowFrame(); - df.initDataFrame(retNode, this.p, rtpSession.appIntf - .frameSize(oldest.pkt.getPayloadType())); - return df; - } else { - return null; - } - } - - /** - * Only returns if the buffer is full, i.e. length exceeds - * rtpSession.pktBufBehavior, or if the next packet directly follows the - * previous one returned to the application. - * - * @return first frame in order, null otherwise - */ - private DataFrame bufferedPopFrame() { - PktBufNode retNode = oldest; - /** - * Three scenarios: 1) There are no packets available 2) The first - * packet is vailable and in order 3) The first packet is not the next - * on in the sequence a) We have exceeded the wait buffer b) We wait - */ - // System.out.println(" Debug:" +(retNode != null) + " " + - // (retNode.seqNum == this.lastSeqNumber + 1) - // + " " + ( retNode.seqNum == 0 ) + " " + (this.length > - // this.rtpSession.maxReorderBuffer) - // + " " + (this.lastSeqNumber < 0)); - - // Pop it off, null all references. - if (retNode != null - && (retNode.seqNum == this.lastSeqNumber + 1 - || retNode.seqNum == 0 - || this.length > this.rtpSession.pktBufBehavior || this.lastSeqNumber < 0)) { - - // if(tmpNode.pktCount == compLen) { - if (RTPSession.rtpDebugLevel > 7) { - System.out - .println("<- PktBuffer.popOldestFrame() returns frame"); - } - - DataFrame df = DataFramePool.getInstance().borrowFrame(); - df.initDataFrame(retNode, this.p, rtpSession.appIntf - .frameSize(oldest.pkt.getPayloadType())); - - // DataFrame df = new DataFrame(retNode, this.p, 1); - popFrameQueueCleanup(retNode, df.lastSeqNum); - - return df; - - } else { - // If we get here we have little to show for. - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println("<- PktBuffer.popOldestFrame() returns null " - + retNode.seqNum + " " + this.lastSeqNumber); - this.debugPrint(); - } - return null; - } - } - - /** - * Cleans the packet buffer before returning the frame, i.e. making sure the - * queue has a head etc. - * - * @param retNode - * the node that is about to be popped - * @param highestSeq - * the highest sequence number returned to the application - */ - private void popFrameQueueCleanup(PktBufNode retNode, int highestSeq) { - if (1 == length) { - // There's only one frame - newest = null; - oldest = null; - } else { - // There are more frames - oldest = oldest.prevFrameQueueNode; - oldest.nextFrameQueueNode = null; - } - - // Update counters - length--; - - // Find the highest sequence number associated with this timestamp - this.lastSeqNumber = highestSeq; - this.lastTimestamp = retNode.timeStamp; - } - - /** - * Returns the length of the packetbuffer. - * - * @return number of frames (complete or not) in packetbuffer. - */ - protected int getLength() { - return length; - } - - /** - * Checks whether a packet is not too late, i.e. the next packet has already - * been returned. - * - * @param timeStamp - * the RTP timestamp of the packet under consideration - * @param seqNum - * the sequence number of the packet under consideration - * @return true if newer packets have not been handed to the application - */ - protected boolean pktOnTime(long timeStamp, int seqNum) { - if (this.lastSeqNumber == -1) { - // First packet - return true; - } else { - if (seqNum >= this.lastSeqNumber) { - if (this.lastSeqNumber < 3 && timeStamp < this.lastTimestamp) { - return false; - } - } else { - if (seqNum > 3 || timeStamp < this.lastTimestamp) { - return false; - } - } - } - return true; - } - - /** - * Prints out the packet buffer, oldest node first (on top). - */ - protected void debugPrint() { - System.out.println("PktBuffer.debugPrint() : length " + length - + " SSRC " + SSRC + " lastSeqNum:" + lastSeqNumber); - PktBufNode tmpNode = oldest; - int i = 0; - while (tmpNode != null) { - // String str = tmpNode.timeStamp.toString(); - System.out.println(" " + i + " seqNum:" + tmpNode.seqNum - + " timeStamp: " + tmpNode.timeStamp + " pktCount:" - + tmpNode.pktCount); - i++; - tmpNode = tmpNode.prevFrameQueueNode; - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/README.txt --- a/src/jlibrtp/README.txt Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -jlibrtp - Java RTP Library - -Kepp, Arne -ak2618@columbia.edu - -Columbia University -New York, NY 10027 -USA - -This library was started as a term project in VoIP Security, a class taught by -Prof. Henning Schulzrinne at Columbia University. Version 0.1 (not released as such) -was written by Vaishnav Janardhan (vj2135@columbia.edu) and Arne Kepp (ak2618@columbia.edu). - -This version was rewritten by Arne Kepp, as a student project under the supervision of -Prof. Henning Schulzrinne, Columbia University. - -------Abstract -jlibrtp is a library that implements the Real-Time Transport Protocol (RTP), -a well-established standard for streaming media across IP-based networks, in Java. -The purpose of this library is to make it easy for application developers to -create applications for peer to peer streaming of audio, video and other data. -In addition, developers will need a protocol to establish contact with peers, -such as Session Initialization Protocol (SIP) and/or SDP. - -The library accepts any kind of binary data, handles packet parsing and reordering, -maintains a participant database and the control connection associated with the -protocol. The application is notified of received data through a callback-interface. -The library supports IPv4, IPv6 and multicast. It does currently not support encryption, -and should not be used in cases where confidentiality is important before this has -been remedied. - -Please refer to http://jlibrtp.org for more information and newer versions. - -The library requires Sun Microsystems Java 1.5.0 or greater, or equivalent. - -The Library is licensed under the GNU Lesser General Public License, see LICENSE.txt - -The demonstration programs can be compiled as follows: -javac ./jlibrtpDemos/SoundSenderDemo.java jlibrtp/*.java \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTCPAVPFIntf.java --- a/src/jlibrtp/RTCPAVPFIntf.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package jlibrtp; - -/** - * This is the callback interface for the AVPF profile (RFC 4585) - * - * It is optional, you do not have to register it. - * - * If there are specific events you wish to ignore, you can simply implement - * empty functions. - * - * These are all syncrhonous, make sure to return quickly or do the handling in - * a new thread. - * - * @author Arne Kepp - */ -public interface RTCPAVPFIntf { - - /** - * This function is called when a Picture Loss Indication (PLI, FMT = 1) is - * received - * - * @param ssrcPacketSender - * the SSRC of the participant reporting loss of picture - */ - public void PSFBPktPictureLossReceived(long ssrcPacketSender); - - /** - * This function is called when a Slice Loss Indication (SLI, FMT=2) is - * received - * - * @param ssrcPacketSender - * the SSRC of the participant reporting loss of slice(s) - * @param sliceFirst - * macroblock address of first macroblock - * @param sliceNumber - * number of lost macroblocks, in scan order - * @param slicePictureId - * the six least significant bits of the picture identifier - */ - public void PSFBPktSliceLossIndic(long ssrcPacketSender, int[] sliceFirst, - int[] sliceNumber, int[] slicePictureId); - - /** - * This function is called when a Reference Picture Selection Indication - * (RPSI, FMT=3) is received - * - * @param ssrcPacketSender - * the SSRC of the participant reporting the selection - * @param rpsiPayloadType - * the RTP payload type related to the RPSI bit string - * @param rpsiBitString - * the RPSI information as natively defined by the video codec - * @param rpsiPaddingBits - * the number of padding bits at the end of the string - */ - public void PSFBPktRefPictureSelIndic(long ssrcPacketSender, - int rpsiPayloadType, byte[] rpsiBitString, int rpsiPaddingBits); - - /** - * This function is called when a Transport Layer Feedback Messages is - * received - * - * @param ssrcPacketSender - * @param alfBitString - */ - public void PSFBPktAppLayerFBReceived(long ssrcPacketSender, - byte[] alfBitString); - - /** - * This function is called when a Transport Layer Feedback Messages is - * received - * - * @param ssrcPacketSender - * @param FMT - * 1: NACK, 0,2-30: unassigned, 31: reserved - * @param packetID - * the RTP sequence number of the lost packet - * @param bitmaskLostPackets - * the bitmask of following lost packets - */ - public void RTPFBPktReceived(long ssrcPacketSender, int FMT, - int[] packetID, int[] bitmaskLostPackets); -} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTCPAppIntf.java --- a/src/jlibrtp/RTCPAppIntf.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package jlibrtp; - -/** - * This is the callback interface for RTCP packets. - * - * It is optional, you do not have to register it. - * - * If there are specific events you wish to ignore, you can simply implement - * empty functions. - * - * These are all syncrhonous, make sure to return quickly or do the handling in - * a new thread. - * - * @author Arne Kepp - */ -public interface RTCPAppIntf { - - /** - * This function is called whenever a Sender Report (SR) packet is received - * and returns unmodified values. - * - * A sender report may optionally include Receiver Reports (RR), which are - * returned as arrays. Index i corresponds to the same report throughout all - * of the arrays. - * - * @param ssrc - * the (SR) SSRC of the sender - * @param ntpHighOrder - * (SR) NTP high order - * @param ntpLowOrder - * (SR) NTP low order - * @param rtpTimestamp - * (SR) RTP timestamp corresponding to the NTP timestamp - * @param packetCount - * (SR) Packets sent since start of session - * @param octetCount - * (SR) Octets sent since start of session - * @param reporteeSsrc - * (RR) SSRC of sender the receiver is reporting in - * @param lossFraction - * (RR) Loss fraction, see RFC 3550 - * @param cumulPacketsLost - * (RR) Cumulative number of packets lost - * @param extHighSeq - * (RR) Extended highest sequence RTP packet received - * @param interArrivalJitter - * (RR) Interarrival jitter, see RFC 3550 - * @param lastSRTimeStamp - * (RR) RTP timestamp when last SR was received - * @param delayLastSR - * (RR) Delay, in RTP, since last SR was received - */ - public void SRPktReceived(long ssrc, long ntpHighOrder, long ntpLowOrder, - long rtpTimestamp, long packetCount, - long octetCount, - // Get the receiver reports, if any - long[] reporteeSsrc, int[] lossFraction, int[] cumulPacketsLost, - long[] extHighSeq, long[] interArrivalJitter, - long[] lastSRTimeStamp, long[] delayLastSR); - - /** - * This function is called whenever a Receiver Report (SR) packet is - * received and returns unmodified values. - * - * A receiver report may optionally include report blocks, which are - * returned as arrays. Index i corresponds to the same report throughout all - * of the arrays. - * - * @param reporterSsrc - * SSRC of the receiver reporting - * @param reporteeSsrc - * (RR) SSRC of sender the receiver is reporting in - * @param lossFraction - * (RR) Loss fraction, see RFC 3550 - * @param cumulPacketsLost - * (RR) Cumulative number of packets lost - * @param extHighSeq - * (RR) Extended highest sequence RTP packet received - * @param interArrivalJitter - * (RR) Interarrival jitter, see RFC 3550 - * @param lastSRTimeStamp - * (RR) RTP timestamp when last SR was received - * @param delayLastSR - * (RR) Delay, in RTP, since last SR was received - */ - public void RRPktReceived(long reporterSsrc, long[] reporteeSsrc, - int[] lossFraction, int[] cumulPacketsLost, long[] extHighSeq, - long[] interArrivalJitter, long[] lastSRTimeStamp, - long[] delayLastSR); - - /** - * This function is called whenever a Source Description (SDES) packet is - * received. - * - * It currently returns the updated participants AFTER they have been - * updated. - * - * @param relevantParticipants - * participants mentioned in the SDES packet - */ - public void SDESPktReceived(Participant[] relevantParticipants); - - /** - * This function is called whenever a Bye (BYE) packet is received. - * - * The participants will automatically be deleted from the participant - * database after some time, but in the mean time the application may still - * receive RTP packets from this source. - * - * @param relevantParticipants - * participants whose SSRC was in the packet - * @param reason - * the reason provided in the packet - */ - public void BYEPktReceived(Participant[] relevantParticipants, String reason); - - /** - * This function is called whenever an Application (APP) packet is received. - * - * @param part - * the participant associated with the SSRC - * @param subtype - * specified in the packet - * @param name - * ASCII description of packet - * @param data - * in the packet - */ - public void APPPktReceived(Participant part, int subtype, byte[] name, - byte[] data); -} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTCPReceiverThread.java --- a/src/jlibrtp/RTCPReceiverThread.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,446 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetSocketAddress; -import java.util.Enumeration; -import java.util.Iterator; - -import org.sipdroid.net.tools.DatagramPool; -import org.sipdroid.net.tools.GenericPool; - -/** - * This thread hangs on the RTCP socket and waits for new packets - * - * @author Arne Kepp - * - */ -public class RTCPReceiverThread extends Thread { - /** Parent RTP Session */ - private RTPSession rtpSession = null; - /** Parent RTCP Session */ - private RTCPSession rtcpSession = null; - - private GenericPool rtcpPacketPool; - - /** - * Constructor for new thread - * - * @param rtcpSession - * parent RTCP session - * @param rtpSession - * parent RTP session - */ - RTCPReceiverThread(RTCPSession rtcpSession, RTPSession rtpSession) { - this.rtpSession = rtpSession; - this.rtcpSession = rtcpSession; - - rtcpPacketPool = new GenericPool(10); - - if (RTPSession.rtpDebugLevel > 1) { - System.out.println("<-> RTCPReceiverThread created"); - } - - } - - /** - * Find out whether a participant with this SSRC is known. - * - * If the user is unknown, and the system is operating in unicast mode, try - * to match the ip-address of the sender to the ip address of a previously - * unmatched target - * - * @param ssrc - * the SSRC of the participant - * @param packet - * the packet that notified us - * @return the relevant participant, possibly newly created - */ - private Participant findParticipant(long ssrc, DatagramPacket packet) { - Participant p = rtpSession.partDb.getParticipant(ssrc); - if (p == null) { - Enumeration enu = rtpSession.partDb.getParticipants(); - while (enu.hasMoreElements()) { - Participant tmp = (Participant) enu.nextElement(); - if (tmp.ssrc < 0 - && (tmp.rtcpAddress.getAddress().equals( - packet.getAddress()) || tmp.rtpAddress - .getAddress().equals(packet.getAddress()))) { - - // Best guess - System.out - .println("RTCPReceiverThread: Got an unexpected packet from SSRC:" - + ssrc - + " @" - + packet.getAddress().toString() - + ", WAS able to match it."); - - tmp.ssrc = ssrc; - return tmp; - } - } - // Create an unknown sender - System.out - .println("RTCPReceiverThread: Got an unexpected packet from SSRC:" - + ssrc - + " @" - + packet.getAddress().toString() - + ", was NOT able to match it."); - p = new Participant((InetSocketAddress) null, - (InetSocketAddress) packet.getSocketAddress(), ssrc); - rtpSession.partDb.addParticipant(2, p); - } - return p; - } - - /** - * Parse a received UDP packet - * - * Perform the header checks and extract the RTCP packets in it - * - * @param packet - * the packet to be parsed - * @return -1 if there was a problem, 0 if successfully parsed - */ - private int parsePacket(DatagramPacket packet) { - - if (packet.getLength() % 4 != 0) { - if (RTPSession.rtcpDebugLevel > 2) { - System.out - .println("RTCPReceiverThread.parsePacket got packet that had length " - + packet.getLength()); - } - return -1; - } else { - byte[] rawPkt = packet.getData(); - - // Parse the received compound RTCP (?) packet - CompRtcpPkt compPkt = rtcpPacketPool.borrowItem(); - compPkt.init(rawPkt, packet.getLength(), - (InetSocketAddress) packet.getSocketAddress(), rtpSession); - - if (this.rtpSession.debugAppIntf != null) { - String intfStr; - - if (rtpSession.mcSession) { - intfStr = this.rtcpSession.rtcpMCSock - .getLocalSocketAddress().toString(); - } else { - intfStr = this.rtpSession.rtpSock.getLocalSocketAddress() - .toString(); - } - - if (compPkt.problem == 0) { - String str = new String( - "Received compound RTCP packet of size " - + packet.getLength() + " from " - + packet.getSocketAddress().toString() - + " via " + intfStr + " containing " - + compPkt.rtcpPkts.size() + " packets"); - - this.rtpSession.debugAppIntf.packetReceived(1, - (InetSocketAddress) packet.getSocketAddress(), str); - } else { - String str = new String( - "Received invalid RTCP packet of size " - + packet.getLength() + " from " - + packet.getSocketAddress().toString() - + " via " + intfStr + ": " - + this.debugErrorString(compPkt.problem)); - - this.rtpSession.debugAppIntf.packetReceived(-2, - (InetSocketAddress) packet.getSocketAddress(), str); - } - } - - if (RTPSession.rtcpDebugLevel > 5) { - Iterator iter = compPkt.rtcpPkts.iterator(); - String str = " "; - while (iter.hasNext()) { - RtcpPkt aPkt = iter.next(); - str += (aPkt.getClass().toString() + ":" + aPkt.itemCount + ", "); - } - System.out.println("<-> RTCPReceiverThread.parsePacket() from " - + packet.getSocketAddress().toString() + str); - } - - // Loop over the information - Iterator iter = compPkt.rtcpPkts.iterator(); - - long curTime = System.currentTimeMillis(); - - while (iter.hasNext()) { - RtcpPkt aPkt = (RtcpPkt) iter.next(); - - // Our own packets should already have been filtered out. - if (aPkt.ssrc == rtpSession.ssrc) { - System.out - .println("RTCPReceiverThread() received RTCP packet" - + " with conflicting SSRC from " - + packet.getSocketAddress().toString()); - rtpSession.resolveSsrcConflict(); - return -1; - } - - /** Receiver Reports **/ - if (aPkt.getClass() == RtcpPktRR.class) { - RtcpPktRR rrPkt = (RtcpPktRR) aPkt; - - Participant p = findParticipant(rrPkt.ssrc, packet); - p.lastRtcpPkt = curTime; - - if (rtpSession.rtcpAppIntf != null) { - rtpSession.rtcpAppIntf.RRPktReceived(rrPkt.ssrc, - rrPkt.reporteeSsrc, rrPkt.lossFraction, - rrPkt.lostPktCount, rrPkt.extHighSeqRecv, - rrPkt.interArvJitter, rrPkt.timeStampLSR, - rrPkt.delaySR); - } - - /** Sender Reports **/ - } else if (aPkt.getClass() == RtcpPktSR.class) { - RtcpPktSR srPkt = (RtcpPktSR) aPkt; - - Participant p = findParticipant(srPkt.ssrc, packet); - p.lastRtcpPkt = curTime; - - if (p != null) { - - if (p.ntpGradient < 0 && p.lastNtpTs1 > -1) { - // Calculate gradient NTP vs RTP - long newTime = StaticProcs.undoNtpMess( - srPkt.ntpTs1, srPkt.ntpTs2); - p.ntpGradient = ((double) (newTime - p.ntpOffset)) - / ((double) srPkt.rtpTs - p.lastSRRtpTs); - if (RTPSession.rtcpDebugLevel > 4) { - System.out - .println("RTCPReceiverThread calculated NTP vs RTP gradient: " - + Double - .toString(p.ntpGradient)); - } - } else { - // Calculate sum of ntpTs1 and ntpTs2 in - // milliseconds - p.ntpOffset = StaticProcs.undoNtpMess(srPkt.ntpTs1, - srPkt.ntpTs2); - p.lastNtpTs1 = srPkt.ntpTs1; - p.lastNtpTs2 = srPkt.ntpTs2; - p.lastSRRtpTs = srPkt.rtpTs; - } - - // For the next RR - p.timeReceivedLSR = curTime; - p.setTimeStampLSR(srPkt.ntpTs1, srPkt.ntpTs2); - - } - - if (rtpSession.rtcpAppIntf != null) { - if (srPkt.rReports != null) { - rtpSession.rtcpAppIntf.SRPktReceived(srPkt.ssrc, - srPkt.ntpTs1, srPkt.ntpTs2, srPkt.rtpTs, - srPkt.sendersPktCount, - srPkt.sendersPktCount, - srPkt.rReports.reporteeSsrc, - srPkt.rReports.lossFraction, - srPkt.rReports.lostPktCount, - srPkt.rReports.extHighSeqRecv, - srPkt.rReports.interArvJitter, - srPkt.rReports.timeStampLSR, - srPkt.rReports.delaySR); - } else { - rtpSession.rtcpAppIntf.SRPktReceived(srPkt.ssrc, - srPkt.ntpTs1, srPkt.ntpTs2, srPkt.rtpTs, - srPkt.sendersPktCount, - srPkt.sendersPktCount, null, null, null, - null, null, null, null); - } - } - - /** Source Descriptions **/ - } else if (aPkt.getClass() == RtcpPktSDES.class) { - RtcpPktSDES sdesPkt = (RtcpPktSDES) aPkt; - - // The the participant database is updated - // when the SDES packet is reconstructed by CompRtcpPkt - if (rtpSession.rtcpAppIntf != null) { - rtpSession.rtcpAppIntf - .SDESPktReceived(sdesPkt.participants); - } - - /** Bye Packets **/ - } else if (aPkt.getClass() == RtcpPktBYE.class) { - RtcpPktBYE byePkt = (RtcpPktBYE) aPkt; - - long time = System.currentTimeMillis(); - Participant[] partArray = new Participant[byePkt.ssrcArray.length]; - - for (int i = 0; i < byePkt.ssrcArray.length; i++) { - partArray[i] = rtpSession.partDb - .getParticipant(byePkt.ssrcArray[i]); - if (partArray[i] != null) - partArray[i].timestampBYE = time; - } - - if (rtpSession.rtcpAppIntf != null) { - rtpSession.rtcpAppIntf.BYEPktReceived(partArray, - new String(byePkt.reason)); - } - - /** Application specific Packets **/ - } else if (aPkt.getClass() == RtcpPktAPP.class) { - RtcpPktAPP appPkt = (RtcpPktAPP) aPkt; - - Participant part = findParticipant(appPkt.ssrc, packet); - - if (rtpSession.rtcpAppIntf != null) { - rtpSession.rtcpAppIntf.APPPktReceived(part, - appPkt.itemCount, appPkt.pktName, - appPkt.pktData); - } - } - - } - } - return 0; - } - - /** - * Returns a legible message when an error occurs - * - * @param errorCode - * the internal error code, commonly negative of packet type - * @return a string that is hopefully somewhat informative - */ - private String debugErrorString(int errorCode) { - String aStr = ""; - switch (errorCode) { - case -1: - aStr = "The first packet was not of type SR or RR."; - break; - case -2: - aStr = "The padding bit was set for the first packet."; - break; - case -200: - aStr = " Error parsing Sender Report packet."; - break; - case -201: - aStr = " Error parsing Receiver Report packet."; - break; - case -202: - aStr = " Error parsing SDES packet"; - break; - case -203: - aStr = " Error parsing BYE packet."; - break; - case -204: - aStr = " Error parsing Application specific packet."; - break; - case -205: - aStr = " Error parsing RTP Feedback packet."; - break; - case -206: - aStr = " Error parsing Payload-Specific Feedback packet."; - break; - default: - aStr = "Unknown error code " + errorCode + "."; - } - - return aStr; - } - - /** - * Start the RTCP receiver thread. - * - * It will 1) run when it receives a packet 2) parse the packet 3) call any - * relevant callback functions, update database 4) block until the next one - * arrives. - */ - public void run() { - if (RTPSession.rtcpDebugLevel > 1) { - if (rtpSession.mcSession) { - System.out - .println("-> RTCPReceiverThread.run() starting on MC " - + rtcpSession.rtcpMCSock.getLocalPort()); - } else { - System.out.println("-> RTCPReceiverThread.run() starting on " - + rtcpSession.rtcpSock.getLocalPort()); - } - } - - while (!rtpSession.endSession) { - - if (RTPSession.rtcpDebugLevel > 4) { - if (rtpSession.mcSession) { - System.out - .println("-> RTCPReceiverThread.run() waiting for packet on MC " - + rtcpSession.rtcpMCSock.getLocalPort()); - } else { - System.out - .println("-> RTCPReceiverThread.run() waiting for packet on " - + rtcpSession.rtcpSock.getLocalPort()); - } - } - - // Prepare a packet - DatagramPacket packet = DatagramPool.getInstance().borrowPacket(); - - // Wait for it to arrive - if (!rtpSession.mcSession) { - // Unicast - try { - rtcpSession.rtcpSock.receive(packet); - } catch (IOException e) { - if (!rtpSession.endSession) { - e.printStackTrace(); - } else { - continue; - } - } - } else { - // Multicast - try { - rtcpSession.rtcpMCSock.receive(packet); - } catch (IOException e) { - if (!rtpSession.endSession) { - e.printStackTrace(); - } else { - continue; - } - } - } - - // Check whether this is one of our own - if ((rtpSession.mcSession && !packet.getSocketAddress().equals( - rtcpSession.rtcpMCSock)) - || !packet.getSocketAddress().equals(rtcpSession.rtcpSock)) { - // System.out.println("Packet received from: " + - // packet.getSocketAddress().toString()); - parsePacket(packet); - // rtpSession.partDb.debugPrint(); - } - } - - if (RTPSession.rtcpDebugLevel > 1) { - System.out.println("<-> RTCPReceiverThread terminating"); - } - } - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTCPSenderThread.java --- a/src/jlibrtp/RTCPSenderThread.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,496 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.DatagramPacket; -import java.net.InetSocketAddress; -import java.util.Enumeration; -import java.util.Iterator; - -/** - * This thread sends scheduled RTCP packets - * - * It also performs maintenance of various queues and the participant database. - * - * @author Arne Kepp - * - */ -public class RTCPSenderThread extends Thread { - /** Parent RTP Session */ - private RTPSession rtpSession = null; - /** Parent RTCP Session */ - private RTCPSession rtcpSession = null; - - /** Whether we have sent byes for the last conflict */ - private boolean byesSent = false; - - /** - * Constructor for new thread - * - * @param rtcpSession - * parent RTCP session - * @param rtpSession - * parent RTP session - */ - protected RTCPSenderThread(RTCPSession rtcpSession, RTPSession rtpSession) { - this.rtpSession = rtpSession; - this.rtcpSession = rtcpSession; - if (RTPSession.rtpDebugLevel > 1) { - System.out.println("<-> RTCPSenderThread created"); - } - } - - /** - * Send BYE messages to all the relevant participants - * - */ - protected void sendByes() { - // Create the packet - CompRtcpPkt compPkt = new CompRtcpPkt(); - - // Need a SR for validation - RtcpPktSR srPkt = new RtcpPktSR(this.rtpSession.ssrc, - this.rtpSession.sentPktCount, this.rtpSession.sentOctetCount, - null); - compPkt.addPacket(srPkt); - - byte[] reasonBytes; - - // Add the actualy BYE Pkt - long[] ssrcArray = { this.rtpSession.ssrc }; - if (rtpSession.conflict) { - reasonBytes = "SSRC collision".getBytes(); - } else { - reasonBytes = "jlibrtp says bye bye!".getBytes(); - } - RtcpPktBYE byePkt = new RtcpPktBYE(ssrcArray, reasonBytes); - - compPkt.addPacket(byePkt); - - // Send it off - if (rtpSession.mcSession) { - mcSendCompRtcpPkt(compPkt); - } else { - Iterator iter = rtpSession.partDb - .getUnicastReceivers(); - - while (iter.hasNext()) { - Participant part = (Participant) iter.next(); - if (part.rtcpAddress != null) - sendCompRtcpPkt(compPkt, part.rtcpAddress); - } - // System.out.println("SENT BYE PACKETS!!!!!"); - } - } - - /** - * Multicast version of sending a Compound RTCP packet - * - * @param pkt - * the packet to best - * @return 0 is successful, -1 otherwise - */ - protected int mcSendCompRtcpPkt(CompRtcpPkt pkt) { - byte[] pktBytes = pkt.encode(); - DatagramPacket packet; - - // Create datagram - try { - packet = new DatagramPacket(pktBytes, pktBytes.length, - rtpSession.mcGroup, rtcpSession.rtcpMCSock.getPort()); - } catch (Exception e) { - System.out - .println("RCTPSenderThread.MCSendCompRtcpPkt() packet creation failed."); - e.printStackTrace(); - return -1; - } - - // Send packet - if (RTPSession.rtcpDebugLevel > 5) { - System.out - .println("<-> RTCPSenderThread.SendCompRtcpPkt() multicast"); - } - try { - rtcpSession.rtcpMCSock.send(packet); - // Debug - if (this.rtpSession.debugAppIntf != null) { - this.rtpSession.debugAppIntf.packetSent(3, - (InetSocketAddress) packet.getSocketAddress(), - new String("Sent multicast RTCP packet of size " - + packet.getLength() - + " to " - + packet.getSocketAddress().toString() - + " via " - + this.rtcpSession.rtcpMCSock - .getLocalSocketAddress().toString())); - } - } catch (Exception e) { - System.out - .println("RCTPSenderThread.MCSendCompRtcpPkt() multicast failed."); - e.printStackTrace(); - return -1; - } - return packet.getLength(); - } - - /** - * Unicast version of sending a Compound RTCP packet - * - * @param pkt - * the packet to best - * @param receiver - * the socket address of the recipient - * @return 0 is successful, -1 otherwise - */ - protected int sendCompRtcpPkt(CompRtcpPkt pkt, InetSocketAddress receiver) { - byte[] pktBytes = pkt.encode(); - DatagramPacket packet; - - // Create datagram - try { - // System.out.println("receiver: " + receiver); - packet = new DatagramPacket(pktBytes, pktBytes.length, receiver); - } catch (Exception e) { - System.out - .println("RCTPSenderThread.SendCompRtcpPkt() packet creation failed."); - e.printStackTrace(); - return -1; - } - - // Send packet - if (RTPSession.rtcpDebugLevel > 5) { - Iterator iter = pkt.rtcpPkts.iterator(); - String str = " "; - while (iter.hasNext()) { - RtcpPkt aPkt = iter.next(); - str += (aPkt.getClass().toString() + ":" + aPkt.itemCount + ", "); - } - System.out - .println("<-> RTCPSenderThread.SendCompRtcpPkt() unicast to " - + receiver + str); - } - try { - rtcpSession.rtcpSock.send(packet); - // Debug - if (this.rtpSession.debugAppIntf != null) { - this.rtpSession.debugAppIntf.packetSent(2, - (InetSocketAddress) packet.getSocketAddress(), - new String("Sent unicast RTCP packet of size " - + packet.getLength() - + " to " - + packet.getSocketAddress().toString() - + " via " - + this.rtcpSession.rtcpSock - .getLocalSocketAddress().toString())); - } - } catch (Exception e) { - System.out - .println("RTCPSenderThread.SendCompRtcpPkt() unicast failed."); - e.printStackTrace(); - return -1; - } - return packet.getLength(); - } - - /** - * Check whether we can send an immediate feedback packet to this person - * - * @param ssrc - * SSRC of participant - */ - protected void reconsiderTiming(long ssrc) { - Participant part = this.rtpSession.partDb.getParticipant(ssrc); - - if (part != null && this.rtcpSession.fbSendImmediately()) { - CompRtcpPkt compPkt = preparePacket(part, false); - /*********** Send the packet ***********/ - // Keep track of sent packet length for average; - int datagramLength; - if (rtpSession.mcSession) { - datagramLength = this.mcSendCompRtcpPkt(compPkt); - } else { - // part.debugPrint(); - datagramLength = this - .sendCompRtcpPkt(compPkt, part.rtcpAddress); - } - /*********** Administrative tasks ***********/ - // Update average packet size - if (datagramLength > 0) { - rtcpSession.updateAvgPacket(datagramLength); - } - } else if (part != null && this.rtcpSession.fbAllowEarly - && this.rtcpSession.fbSendEarly()) { - - // Make sure we dont do it too often - this.rtcpSession.fbAllowEarly = false; - - CompRtcpPkt compPkt = preparePacket(part, true); - /*********** Send the packet ***********/ - // Keep track of sent packet length for average; - int datagramLength; - if (rtpSession.mcSession) { - datagramLength = this.mcSendCompRtcpPkt(compPkt); - } else { - // part.debugPrint(); - datagramLength = this - .sendCompRtcpPkt(compPkt, part.rtcpAddress); - } - /*********** Administrative tasks ***********/ - // Update average packet size - if (datagramLength > 0) { - rtcpSession.updateAvgPacket(datagramLength); - } - rtcpSession.calculateDelay(); - } - - // Out of luck, fb message will have to go with next regular packet - // Sleep for the remaining time. - this.rtcpSession.nextDelay -= System.currentTimeMillis() - - this.rtcpSession.prevTime; - if (this.rtcpSession.nextDelay < 0) - this.rtcpSession.nextDelay = 0; - - } - - /** - * Prepare a packet. The output depends on the participant and how the - * packet is scheduled. - * - * @param part - * the participant to report to - * @param regular - * whether this is a regularly, or early scheduled RTCP packet - * @return compound RTCP packet - */ - protected CompRtcpPkt preparePacket(Participant part, boolean regular) { - /*********** Figure out what we are going to send ***********/ - // Check whether this person has sent RTP packets since the last RR. - boolean incRR = false; - if (part.secondLastRtcpRRPkt > part.lastRtcpRRPkt) { - incRR = true; - part.secondLastRtcpRRPkt = part.lastRtcpRRPkt; - part.lastRtcpRRPkt = System.currentTimeMillis(); - } - - // Are we sending packets? -> add SR - boolean incSR = false; - if (rtpSession.sentPktCount > 0 && regular) { - incSR = true; - } - - /*********** Actually create the packet ***********/ - // Create compound packet - CompRtcpPkt compPkt = new CompRtcpPkt(); - - // If we're sending packets we'll use a SR for header - if (incSR) { - RtcpPktSR srPkt = new RtcpPktSR(this.rtpSession.ssrc, - this.rtpSession.sentPktCount, - this.rtpSession.sentOctetCount, null); - compPkt.addPacket(srPkt); - - if (part.ssrc > 0) { - RtcpPkt[] ar = this.rtcpSession.getFromFbQueue(part.ssrc); - if (ar != null) { - for (int i = 0; i < ar.length; i++) { - compPkt.addPacket(ar[i]); - } - } - } - - } - - // If we got anything from this participant since we sent the 2nd to - // last RtcpPkt - if (incRR || !incSR) { - Participant[] partArray = { part }; - - if (part.receivedPkts < 1) - partArray = null; - - RtcpPktRR rrPkt = new RtcpPktRR(partArray, rtpSession.ssrc); - compPkt.addPacket(rrPkt); - - if (!incSR && part.ssrc > 0) { - RtcpPkt[] ar = this.rtcpSession.getFromFbQueue(part.ssrc); - if (ar != null) { - for (int i = 0; i < ar.length; i++) { - compPkt.addPacket(ar[i]); - } - } - } - } - - // APP packets - if (regular && part.ssrc > 0) { - RtcpPkt[] ar = this.rtcpSession.getFromAppQueue(part.ssrc); - if (ar != null) { - for (int i = 0; i < ar.length; i++) { - compPkt.addPacket(ar[i]); - } - } else { - // Nope - } - } - - // For now we'll stick the SDES on every time, and only for us - // if(regular) { - RtcpPktSDES sdesPkt = new RtcpPktSDES(true, this.rtpSession, null); - compPkt.addPacket(sdesPkt); - // } - - return compPkt; - } - - /** - * Start the RTCP sender thread. - * - * RFC 4585 is more complicated, but in general it will 1) Wait a - * precalculated amount of time 2) Determine the next RTCP recipient 3) - * Construct a compound packet with all the relevant information 4) Send the - * packet 5) Calculate next delay before going to sleep - */ - public void run() { - if (RTPSession.rtcpDebugLevel > 1) { - System.out.println("<-> RTCPSenderThread running"); - } - - // Give the application a chance to register some participants - try { - Thread.sleep(10); - } catch (Exception e) { - System.out.println("RTCPSenderThread didn't get any initial rest."); - } - - // Set up an iterator for the member list - Enumeration enu = null; - Iterator iter = null; - - // TODO Change to rtcpReceivers - if (rtpSession.mcSession) { - enu = rtpSession.partDb.getParticipants(); - } else { - iter = rtpSession.partDb.getUnicastReceivers(); - } - while (!rtpSession.endSession) { - if (RTPSession.rtcpDebugLevel > 5) { - System.out.println("<-> RTCPSenderThread sleeping for " - + rtcpSession.nextDelay + " ms"); - } - - try { - Thread.sleep(rtcpSession.nextDelay); - } catch (Exception e) { - System.out.println("RTCPSenderThread Exception message:" - + e.getMessage()); - // Is the party over? - if (this.rtpSession.endSession) { - continue; - } - - if (rtcpSession.fbWaiting != -1) { - reconsiderTiming(rtcpSession.fbWaiting); - continue; - } - } - - /** Came here the regular way */ - this.rtcpSession.fbAllowEarly = true; - - if (RTPSession.rtcpDebugLevel > 5) { - System.out.println("<-> RTCPSenderThread waking up"); - } - - // Regenerate nextDelay, before anything happens. - rtcpSession.calculateDelay(); - - // We'll wait here until a conflict (if any) has been resolved, - // so that the bye packets for our current SSRC can be sent. - if (rtpSession.conflict) { - if (!this.byesSent) { - sendByes(); - this.byesSent = true; - } - continue; - } - this.byesSent = false; - - // Grab the next person - Participant part = null; - - // Multicast - if (this.rtpSession.mcSession) { - if (!enu.hasMoreElements()) - enu = rtpSession.partDb.getParticipants(); - - if (enu.hasMoreElements()) { - part = enu.nextElement(); - } else { - continue; - } - - // Unicast - } else { - if (!iter.hasNext()) { - iter = rtpSession.partDb.getUnicastReceivers(); - } - - if (iter.hasNext()) { - while (iter.hasNext() - && (part == null || part.rtcpAddress == null)) { - part = iter.next(); - } - } - - if (part == null || part.rtcpAddress == null) - continue; - } - - CompRtcpPkt compPkt = preparePacket(part, true); - - /*********** Send the packet ***********/ - // Keep track of sent packet length for average; - int datagramLength; - if (rtpSession.mcSession) { - datagramLength = this.mcSendCompRtcpPkt(compPkt); - } else { - // part.debugPrint(); - datagramLength = this - .sendCompRtcpPkt(compPkt, part.rtcpAddress); - } - - /*********** Administrative tasks ***********/ - // Update average packet size - if (datagramLength > 0) { - rtcpSession.updateAvgPacket(datagramLength); - } - } - - // Be polite, say Bye to everone - sendByes(); - try { - Thread.sleep(200); - } catch (Exception e) { - } - - if (RTPSession.rtcpDebugLevel > 0) { - System.out.println("<-> RTCPSenderThread terminating"); - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTCPSession.java --- a/src/jlibrtp/RTCPSession.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,565 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.MulticastSocket; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.ListIterator; - -/** - * This class acts as an organizer for most of the information and functions - * pertaining to RTCP packet generation and reception - * - * @author Arne Kepp - * - */ -public class RTCPSession { - /** Parent session */ - protected RTPSession rtpSession = null; - - /** Unicast socket */ - protected DatagramSocket rtcpSock = null; - /** Multicast socket */ - protected MulticastSocket rtcpMCSock = null; - /** Multicast group */ - protected InetAddress mcGroup = null; - - /** RTCP Receiver thread */ - protected RTCPReceiverThread recvThrd = null; - /** RTCP Sender thread */ - protected RTCPSenderThread senderThrd = null; - - /** Previous time a delay was calculated */ - protected long prevTime = System.currentTimeMillis(); - /** Delay between RTCP transmissions, in ms. Initialized in start() */ - protected int nextDelay = -1; // - /** - * The average compound RTCP packet size, in octets, including UDP and IP - * headers - */ - protected int avgPktSize = 200; // - /** Pessimistic case estimate of the current number of senders */ - protected int senderCount = 1; - /** Whether next RTCP packet can be sent early */ - protected boolean fbAllowEarly = false; - /** Feedback queue , index is SSRC of target */ - protected Hashtable> fbQueue = null; - /** APP queue , index is SSRC of target */ - protected Hashtable> appQueue = null; - /** Are we just starting up? */ - protected boolean initial = true; - /** Is there a feedback packet waiting? SSRC of destination */ - protected long fbWaiting = -1; - - /** - * Constructor for unicast sessions - * - * @param parent - * RTPSession that started this - * @param rtcpSocket - * the socket to use for listening and sending - */ - protected RTCPSession(RTPSession parent, DatagramSocket rtcpSocket) { - this.rtcpSock = rtcpSocket; - rtpSession = parent; - } - - /** - * Constructor for multicast sessions - * - * @param parent - * parent RTPSession - * @param rtcpSocket - * parent RTPSession that started this - * @param multicastGroup - * multicast group to bind the socket to - */ - protected RTCPSession(RTPSession parent, MulticastSocket rtcpSocket, - InetAddress multicastGroup) { - mcGroup = multicastGroup; - this.rtcpSock = rtcpSocket; - rtpSession = parent; - } - - /** - * Starts the session, calculates delays and fires up the threads. - * - */ - protected void start() { - // nextDelay = 2500 + rtpSession.random.nextInt(1000) - 500; - this.calculateDelay(); - recvThrd = new RTCPReceiverThread(this, this.rtpSession); - senderThrd = new RTCPSenderThread(this, this.rtpSession); - recvThrd.start(); - senderThrd.start(); - } - - /** - * Send bye packets, handled by RTCP Sender thread - * - */ - protected void sendByes() { - senderThrd.sendByes(); - } - - /** - * Calculate the delay before the next RTCP packet can be sent - * - */ - protected void calculateDelay() { - switch (rtpSession.rtcpMode) { - case 0: - calculateRegularDelay(); - break; - default: - System.out.println("RTCPSession.calculateDelay() unknown .mode"); - } - } - - /** - * Calculates a delay value in accordance with RFC 3550 - * - */ - protected void calculateRegularDelay() { - long curTime = System.currentTimeMillis(); - - if (rtpSession.bandwidth != 0 && !this.initial - && rtpSession.partDb.ssrcTable.size() > 4) { - // RTPs mechanisms for RTCP scalability - int rand = rtpSession.random.nextInt(10000) - 5000; // between -500 - // and +500 - double randDouble = ((double) 1000 + rand) / 1000.0; - - Enumeration enu = rtpSession.partDb.getParticipants(); - while (enu.hasMoreElements()) { - Participant part = enu.nextElement(); - if (part.lastRtpPkt > this.prevTime) - senderCount++; - } - - double bw; - if (rtpSession.rtcpBandwidth > -1) { - bw = rtpSession.rtcpBandwidth; - } else { - bw = rtpSession.bandwidth * 0.05; - } - if (senderCount * 2 > rtpSession.partDb.ssrcTable.size()) { - if (rtpSession.lastTimestamp > this.prevTime) { - // We're a sender - double numerator = ((double) this.avgPktSize) - * ((double) senderCount); - double denominator = 0.25 * bw; - this.nextDelay = (int) Math.round((numerator / denominator) - * randDouble); - } else { - // We're a receiver - double numerator = ((double) this.avgPktSize) - * ((double) rtpSession.partDb.ssrcTable.size()); - double denominator = 0.75 * bw; - this.nextDelay = (int) Math.round((numerator / denominator) - * randDouble); - } - } else { - double numerator = ((double) this.avgPktSize) - * ((double) rtpSession.partDb.ssrcTable.size()); - ; - double denominator = bw; - this.nextDelay = (int) Math - .round(1000.0 * (numerator / denominator)) - * (1000 + rand); - } - } else { - // Not enough data to scale, use random values - int rand = rtpSession.random.nextInt(1000) - 500; // between -500 - // and +500 - if (this.initial) { - // 2.5 to 3.5 seconds, randomly - this.nextDelay = 3000 + rand; - this.initial = false; - } else { - // 4.5 to 5.5 seconds, randomly - this.nextDelay = 5500 + rand; - } - - } - - // preflight check - if (this.nextDelay < 1000) { - int rand = rtpSession.random.nextInt(1000) - 500; // between -500 - // and +500 - System.out - .println("RTCPSession.calculateDelay() nextDelay was too short (" - + this.nextDelay - + "ms), setting to " - + (this.nextDelay = 2000 + rand)); - } - this.prevTime = curTime; - } - - /** - * Update the average packet size - * - * @param length - * of latest packet - */ - synchronized protected void updateAvgPacket(int length) { - double tempAvg = (double) this.avgPktSize; - tempAvg = (15 * tempAvg + ((double) length)) / 16; - this.avgPktSize = (int) tempAvg; - } - - /** - * Adds an RTCP APP (application) packet to the queue - * - * @param targetSsrc - * the SSRC of the recipient - * @param aPkt - */ - synchronized protected void addToAppQueue(long targetSsrc, RtcpPktAPP aPkt) { - aPkt.time = System.currentTimeMillis(); - - if (this.appQueue == null) - this.appQueue = new Hashtable>(); - - LinkedList ll = this.appQueue.get(targetSsrc); - if (ll == null) { - // No list, create and add - ll = new LinkedList(); - this.appQueue.put(targetSsrc, ll); - } - - ll.add(aPkt); - } - - /** - * Adds an RTCP APP (application) packet to the queue - * - * @param targetSsrc - * the SSRC of the recipient - * @return array of RTCP Application packets - */ - synchronized protected RtcpPktAPP[] getFromAppQueue(long targetSsrc) { - if (this.appQueue == null) - return null; - - LinkedList ll = this.appQueue.get(targetSsrc); - if (ll == null || ll.isEmpty()) { - return null; - } else { - RtcpPktAPP[] ret = new RtcpPktAPP[ll.size()]; - ListIterator li = ll.listIterator(); - int i = 0; - while (li.hasNext()) { - ret[i] = li.next(); - i++; - } - return ret; - } - } - - /** - * Cleans the TCP APP (application) packet queues of any packets that are - * too old, defined as 60 seconds since insertion. - * - * @param ssrc - * The SSRC of the user who has left, negative value -> general - * cleanup - */ - synchronized protected void cleanAppQueue(long ssrc) { - if (this.appQueue == null) - return; - - if (ssrc > 0) { - this.appQueue.remove(ssrc); - } else { - Enumeration> enu = this.appQueue.elements(); - long curTime = System.currentTimeMillis(); - - while (enu.hasMoreElements()) { - ListIterator li = enu.nextElement().listIterator(); - while (li.hasNext()) { - RtcpPkt aPkt = li.next(); - // Remove after 60 seconds - if (curTime - aPkt.time > 60000) { - li.remove(); - } - } - } - } - } - - /** - * Check the feedback queue for similar packets and adds the new packet if - * it is not redundant - * - * @param aPkt - * @return 0 if the packet was added, 1 if it was dropped - */ - synchronized protected int addToFbQueue(long targetSsrc, RtcpPkt aPkt) { - if (this.fbQueue == null) - this.fbQueue = new Hashtable>(); - - LinkedList ll = this.fbQueue.get(targetSsrc); - if (ll == null) { - // No list, create and add - ll = new LinkedList(); - ll.add(aPkt); - this.fbQueue.put(targetSsrc, ll); - } else { - // Check for matching packets, else add to end - ListIterator li = ll.listIterator(); - while (li.hasNext()) { - RtcpPkt tmp = li.next(); - if (equivalent(tmp, aPkt)) - return -1; - } - ll.addLast(aPkt); - } - return 0; - } - - /** - * Checks whether there are ny feedback packets waiting to be sent. - * - * @param ssrc - * of the participant we are notifying - * @return all relevant feedback packets, or null - */ - synchronized protected RtcpPkt[] getFromFbQueue(long ssrc) { - if (this.fbQueue == null) - return null; - - LinkedList ll = this.fbQueue.get(ssrc); - - if (ll == null) - return null; - - ListIterator li = ll.listIterator(); - if (li.hasNext()) { - long curTime = System.currentTimeMillis(); - long maxDelay = curTime - rtpSession.fbMaxDelay; - long keepDelay = curTime - 2000; - int count = 0; - - // TODO below the indeces should be collected instead of looping - // twice - - // Clean out what we dont want and count what we want - while (li.hasNext()) { - RtcpPkt aPkt = li.next(); - if (aPkt.received) { - // This is a packet received, we keep these for - // 2000ms to avoid redundant feedback - if (aPkt.time < keepDelay) - li.remove(); - } else { - // This is a packet we havent sent yet - if (aPkt.time < maxDelay) { - li.remove(); - } else { - count++; - } - } - } - - // Gather what we want to return - if (count != 0) { - li = ll.listIterator(); - RtcpPkt[] ret = new RtcpPkt[count]; - - while (count > 0) { - RtcpPkt aPkt = li.next(); - if (!aPkt.received) { - ret[ret.length - count] = aPkt; - count--; - } - } - return ret; - } - } - - return null; - } - - /** - * Cleans the feeback queue of any packets that have expired, ie feedback - * packet that are no longer relevant. - * - * @param ssrc - * The SSRC of the user who has left, negative value -> general - * cleanup - */ - synchronized protected void cleanFbQueue(long ssrc) { - if (this.fbQueue == null) - return; - - if (ssrc > 0) { - this.fbQueue.remove(ssrc); - } else { - Enumeration> enu = this.fbQueue.elements(); - long curTime = System.currentTimeMillis(); - long maxDelay = curTime - rtpSession.fbMaxDelay; - long keepDelay = curTime - 2000; - - while (enu.hasMoreElements()) { - ListIterator li = enu.nextElement().listIterator(); - while (li.hasNext()) { - RtcpPkt aPkt = li.next(); - if (aPkt.received) { - // This is a packet received, we keep these for - // 2000ms to avoid redundant feedback - if (aPkt.time < keepDelay) - li.remove(); - } else { - // This is a packet we havent sent yet - if (aPkt.time < maxDelay) - li.remove(); - } - } - } - } - } - - /** - * Check whether the conditions are satisfied to send a feedbkac packet - * immediately. - * - * @return true if they are, false otherwise - */ - protected boolean fbSendImmediately() { - if (rtpSession.partDb.ssrcTable.size() > this.rtpSession.fbEarlyThreshold - && rtpSession.partDb.receivers.size() > this.rtpSession.fbEarlyThreshold) - return false; - - return true; - } - - /** - * Check whether the conditions are satisfied to send a feedbkac packet - * immediately. - * - * @return true if they are, false otherwise - */ - protected boolean fbSendEarly() { - if (rtpSession.partDb.ssrcTable.size() > this.rtpSession.fbRegularThreshold - && rtpSession.partDb.receivers.size() > this.rtpSession.fbRegularThreshold) - return false; - - return true; - } - - /** - * Wake the sender thread because of this ssrc - * - * @param ssrc - * that has feedback waiting. - */ - protected void wakeSenderThread(long ssrc) { - this.fbWaiting = ssrc; - this.senderThrd.interrupt(); - - // Give it a chance to catch up - try { - Thread.sleep(0, 1); - } catch (Exception e) { - } - ; - } - - /** - * Compares two packets to check whether they are equivalent feedback - * messages, to avoid sending the same feedback to a host twice. - * - * Expect false negatives, but not false positives. - * - * @param one - * packet - * @param two - * packet - * @return true if they are equivalent, false otherwise - */ - private boolean equivalent(RtcpPkt one, RtcpPkt two) { - // Cheap checks - if (one.packetType != two.packetType) - return false; - - if (one.itemCount != two.itemCount) - return false; - - if (one.packetType == 205) { - // RTP Feedback, i.e. a NACK - RtcpPktRTPFB pktone = (RtcpPktRTPFB) one; - RtcpPktRTPFB pkttwo = (RtcpPktRTPFB) two; - - if (pktone.ssrcMediaSource != pkttwo.ssrcMediaSource) - return false; - - if (Arrays.equals(pktone.BLP, pkttwo.BLP) - && Arrays.equals(pktone.BLP, pkttwo.BLP)) - return true; - - return true; - } else if (one.packetType == 206) { - RtcpPktPSFB pktone = (RtcpPktPSFB) one; - RtcpPktPSFB pkttwo = (RtcpPktPSFB) two; - - if (pktone.ssrcMediaSource != pkttwo.ssrcMediaSource) - return false; - - switch (one.itemCount) { - case 1: // Picture Loss Indication - return true; - - case 2: // Slice Loss Indication - // This will not work if the slice loss indicators are in - // different order - if (pktone.sliFirst.length == pkttwo.sliFirst.length - && Arrays.equals(pktone.sliFirst, pkttwo.sliFirst) - && Arrays.equals(pktone.sliNumber, pkttwo.sliNumber) - && Arrays.equals(pktone.sliPictureId, - pkttwo.sliPictureId)) - return true; - break; - case 3: // Reference Picture Selection Indication - if (Arrays.equals(pktone.rpsiBitString, pkttwo.rpsiBitString)) - return true; - break; - case 15: // Application Layer Feedback Messages - // This will not work if the padding scheme is different - if (pktone.sliFirst.length == pkttwo.sliFirst.length - && Arrays.equals(pktone.alfBitString, - pkttwo.alfBitString)) - return true; - break; - default: - - } - return true; - } else { - System.out - .println("!!!! RTCPSession.equivalentPackets() encountered unexpected packet type!"); - } - return false; - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTPAppIntf.java --- a/src/jlibrtp/RTPAppIntf.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package jlibrtp; - -/** - * This is the callback interface for RTP packets. - * - * It is mandatory, but you can inore the data if you like. - * - * @author Arne Kepp - */ -public interface RTPAppIntf { - - /** - * The callback method through which the application will receive data from - * jlibrtp. These calls are synchronous, so you will not receive any new - * packets until this call returns. - * - * @param frame - * the frame containing the data - * @param participant - * the participant from which the data came - */ - public void receiveData(DataFrame frame, Participant participant); - - /** - * The callback method through which the application will receive - * notifications about user updates, additions and byes. Types: 1 - Bye 2 - - * New through RTP, check .getRtpSendSock() 3 - New through RTCP, check - * .getRtcpSendSock() 4 - SDES packet received, check the getCname() etc - * methods 5 - Matched SSRC to ip-address provided by application - * - * @param type - * the type of event - * @param participant - * the participants in question - */ - public void userEvent(int type, Participant[] participant); - - /** - * The callback method through which the application can specify the number - * of packets that make up a frame for a given payload type. - * - * A negative value denotes frames of variable length, so jlibrtp will - * return whatever it has at the time. - * - * In most applications, this function can simply return 1. - * - * This should be implemented as something fast, such as an integer array - * with the indeces being the payload type. - * - * @param payloadType - * the payload type specified in the RTP packet - * @return the number of packets that make up a frame - */ - public int frameSize(int payloadType); -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTPReceiverThread.java --- a/src/jlibrtp/RTPReceiverThread.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,369 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetSocketAddress; -import java.net.SocketException; - -import org.sipdroid.net.tools.DatagramPool; -import org.sipdroid.net.tools.RtpPktPool; - -/** - * The RTP receiver thread waits on the designated UDP socket for new packets. - * - * Once one arrives, it is parsed and tested. We also check the ip-address of - * the sender. If accepted, the packet is added onto the packet buffer of the - * participant. - * - * A separate thread moves the packet from the packet buffer to the application. - * - * @author Arne Kepp - */ -public class RTPReceiverThread extends Thread { - /** Parent RTP Session */ - RTPSession rtpSession = null; - DatagramPool datagramPool = null; - - RTPReceiverThread(RTPSession session) { - rtpSession = session; - datagramPool = DatagramPool.getInstance(); - if (RTPSession.rtpDebugLevel > 1) { - System.out.println("<-> RTPReceiverThread created"); - } - } - public void init() { - if (RTPSession.rtpDebugLevel > 1) { - if (rtpSession.mcSession) { - System.out.println("-> RTPReceiverThread.run() starting on MC " - + rtpSession.rtpMCSock.getLocalPort()); - } else { - System.out.println("-> RTPReceiverThread.run() starting on " - + rtpSession.rtpSock.getLocalPort()); - } - } - - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); - - DatagramPacket packet = datagramPool.borrowPacket(); - try { - rtpSession.rtpSock.setSoTimeout(1); - for (;;) - rtpSession.rtpSock.receive(packet); - } catch (SocketException e2) { - - } catch (IOException e) { - } - datagramPool.returnPacket(packet); - try { - rtpSession.rtpSock.setSoTimeout(1000); - } catch (SocketException e2) { - } - } - - public void readPacketToBuffer() { - if (RTPSession.rtpDebugLevel > 6) { - if (rtpSession.mcSession) { - System.out - .println("-> RTPReceiverThread.run() waiting for MC packet on " - + rtpSession.rtpMCSock.getLocalPort()); - } else { - System.out - .println("-> RTPReceiverThread.run() waiting for packet on " - + rtpSession.rtpSock.getLocalPort()); - } - } - - // Prepare a packet - //DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length); - DatagramPacket packet = datagramPool.borrowPacket(); - // Wait for it to arrive - if (!rtpSession.mcSession) { - // Unicast - try { - rtpSession.rtpSock.receive(packet); - } catch (IOException e) { - if (!rtpSession.endSession) { - e.printStackTrace(); - } else { - return; - } - } - } else { - // Multicast - try { - rtpSession.rtpMCSock.receive(packet); - } catch (IOException e) { - if (!rtpSession.endSession) { - e.printStackTrace(); - } else { - return; - } - } - } - // Parse the received RTP (?) packet - RtpPkt pkt = RtpPktPool.getInstance().borrowPkt(); - pkt.initPacket(packet.getData(), packet.getLength(), packet); - - // Check whether it was valid. - if (pkt == null) { - System.out.println("Received invalid RTP packet. Ignoring"); - return; - } - - long pktSsrc = pkt.getSsrc(); - - // Check for loops and SSRC collisions - if (rtpSession.ssrc == pktSsrc) - rtpSession.resolveSsrcConflict(); - - long[] csrcArray = pkt.getCsrcArray(); - if (csrcArray != null) { - for (int i = 0; i < csrcArray.length; i++) { - if (csrcArray[i] == rtpSession.ssrc) - ; - rtpSession.resolveSsrcConflict(); - } - } - - if (RTPSession.rtpDebugLevel > 17) { - System.out - .println("-> RTPReceiverThread.run() rcvd packet, seqNum " - + pktSsrc); - if (RTPSession.rtpDebugLevel > 10) { - System.out.println("-> RTPReceiverThread.run() payload is " - + pkt.getPayloadLength()); - } - } - - // Find the participant in the database based on SSRC - //Participant part = rtpSession.partDb.getParticipant(pktSsrc); - Participant part = rtpSession.firstPart; - if (part == null) { - InetSocketAddress nullSocket = null; - part = new Participant((InetSocketAddress) packet - .getSocketAddress(), nullSocket, pkt.getSsrc()); - part.unexpected = true; - rtpSession.partDb.addParticipant(1, part); - } - - // Do checks on whether the datagram came from the expected source - // for that SSRC. - - if (part.rtpAddress == null - || packet.getAddress().equals(part.rtpAddress.getAddress())) { - PktBuffer pktBuffer = part.pktBuffer; - - if (pktBuffer != null) { - // A buffer already exists, append to it - pktBuffer.addPkt(pkt); - } else { - // Create a new packet/frame buffer - pktBuffer = new PktBuffer(this.rtpSession, part, pkt); - part.pktBuffer = pktBuffer; - } - } else { - System.out - .println("RTPReceiverThread: Got an unexpected packet from " - + pkt.getSsrc() - + " the sending ip-address was " - + packet.getAddress().toString() - + ", we expected from " - + part.rtpAddress.toString()); - } - - // Statistics for receiver report. - part.updateRRStats(packet.getLength(), pkt); - // Upate liveness - part.lastRtpPkt = System.currentTimeMillis(); - - if (RTPSession.rtpDebugLevel > 5) { - System.out - .println("<-> RTPReceiverThread signalling pktBufDataReady"); - } - - // Signal the thread that pushes data to application - /*rtpSession.pktBufLock.lock(); - try { - rtpSession.pktBufDataReady.signalAll(); - } finally { - rtpSession.pktBufLock.unlock(); - }*/ - } - - public void run() { - if (RTPSession.rtpDebugLevel > 1) { - if (rtpSession.mcSession) { - System.out.println("-> RTPReceiverThread.run() starting on MC " - + rtpSession.rtpMCSock.getLocalPort()); - } else { - System.out.println("-> RTPReceiverThread.run() starting on " - + rtpSession.rtpSock.getLocalPort()); - } - } - - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); - - DatagramPacket packet = datagramPool.borrowPacket(); - try { - rtpSession.rtpSock.setSoTimeout(1); - for (;;) - rtpSession.rtpSock.receive(packet); - } catch (SocketException e2) { - - } catch (IOException e) { - } - datagramPool.returnPacket(packet); - try { - rtpSession.rtpSock.setSoTimeout(0); - } catch (SocketException e2) { - } - while (!rtpSession.endSession) { - if (RTPSession.rtpDebugLevel > 6) { - if (rtpSession.mcSession) { - System.out - .println("-> RTPReceiverThread.run() waiting for MC packet on " - + rtpSession.rtpMCSock.getLocalPort()); - } else { - System.out - .println("-> RTPReceiverThread.run() waiting for packet on " - + rtpSession.rtpSock.getLocalPort()); - } - } - - // Prepare a packet - //DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length); - packet = datagramPool.borrowPacket(); - // Wait for it to arrive - if (!rtpSession.mcSession) { - // Unicast - try { - rtpSession.rtpSock.receive(packet); - } catch (IOException e) { - if (!rtpSession.endSession) { - e.printStackTrace(); - } else { - continue; - } - } - } else { - // Multicast - try { - rtpSession.rtpMCSock.receive(packet); - } catch (IOException e) { - if (!rtpSession.endSession) { - e.printStackTrace(); - } else { - continue; - } - } - } - // Parse the received RTP (?) packet - RtpPkt pkt = RtpPktPool.getInstance().borrowPkt(); - pkt.initPacket(packet.getData(), packet.getLength(), packet); - - // Check whether it was valid. - if (pkt == null) { - System.out.println("Received invalid RTP packet. Ignoring"); - continue; - } - - long pktSsrc = pkt.getSsrc(); - - // Check for loops and SSRC collisions - if (rtpSession.ssrc == pktSsrc) - rtpSession.resolveSsrcConflict(); - - long[] csrcArray = pkt.getCsrcArray(); - if (csrcArray != null) { - for (int i = 0; i < csrcArray.length; i++) { - if (csrcArray[i] == rtpSession.ssrc) - ; - rtpSession.resolveSsrcConflict(); - } - } - - if (RTPSession.rtpDebugLevel > 17) { - System.out - .println("-> RTPReceiverThread.run() rcvd packet, seqNum " - + pktSsrc); - if (RTPSession.rtpDebugLevel > 10) { - System.out.println("-> RTPReceiverThread.run() payload is " - + pkt.getPayloadLength()); - } - } - - // Find the participant in the database based on SSRC - Participant part = rtpSession.partDb.getParticipant(pktSsrc); - - if (part == null) { - InetSocketAddress nullSocket = null; - part = new Participant((InetSocketAddress) packet - .getSocketAddress(), nullSocket, pkt.getSsrc()); - part.unexpected = true; - rtpSession.partDb.addParticipant(1, part); - } - - // Do checks on whether the datagram came from the expected source - // for that SSRC. - if (part.rtpAddress == null - || packet.getAddress().equals(part.rtpAddress.getAddress())) { - PktBuffer pktBuffer = part.pktBuffer; - - if (pktBuffer != null) { - // A buffer already exists, append to it - pktBuffer.addPkt(pkt); - } else { - // Create a new packet/frame buffer - pktBuffer = new PktBuffer(this.rtpSession, part, pkt); - part.pktBuffer = pktBuffer; - } - } else { - System.out - .println("RTPReceiverThread: Got an unexpected packet from " - + pkt.getSsrc() - + " the sending ip-address was " - + packet.getAddress().toString() - + ", we expected from " - + part.rtpAddress.toString()); - } - - // Statistics for receiver report. - part.updateRRStats(packet.getLength(), pkt); - // Upate liveness - part.lastRtpPkt = System.currentTimeMillis(); - - if (RTPSession.rtpDebugLevel > 5) { - System.out - .println("<-> RTPReceiverThread signalling pktBufDataReady"); - } - - // Signal the thread that pushes data to application - rtpSession.pktBufLock.lock(); - try { - rtpSession.pktBufDataReady.signalAll(); - } finally { - rtpSession.pktBufLock.unlock(); - } - - } - } - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RTPSession.java --- a/src/jlibrtp/RTPSession.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1301 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.MulticastSocket; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.Random; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.sipdroid.net.tools.DataFramePool; -import org.sipdroid.net.tools.DatagramPool; -import org.sipdroid.net.tools.PktBufNodePool; -import org.sipdroid.net.tools.RtpPktPool; - -import android.util.Log; - -/** - * The RTPSession object is the core of jlibrtp. - * - * One should be instantiated for every communication channel, i.e. if you send - * voice and video, you should create one for each. - * - * The instance holds a participant database, as well as other information about - * the session. When the application registers with the session, the necessary - * threads for receiving and processing RTP packets are spawned. - * - * RTP Packets are sent synchronously, all other operations are asynchronous. - * - * @author Arne Kepp - */ -public class RTPSession { - /** - * The debug level is final to avoid compilation of if-statements.
0 - * provides no debugging information, 20 provides everything
Debug - * output is written to System.out
Debug level for RTP related things. - */ - final static public int rtpDebugLevel = 1; - /** - * The debug level is final to avoid compilation of if-statements.
0 - * provides no debugging information, 20 provides everything
Debug - * output is written to System.out
Debug level for RTCP related things. - */ - final static public int rtcpDebugLevel = 1; - - /** RTP unicast socket */ - protected DatagramSocket rtpSock = null; - /** RTP multicast socket */ - protected MulticastSocket rtpMCSock = null; - /** RTP multicast group */ - protected InetAddress mcGroup = null; - - // Internal state - /** Whether this session is a multicast session or not */ - protected boolean mcSession = false; - /** Current payload type, can be changed by application */ - protected int payloadType = 0; - /** SSRC of this session */ - protected long ssrc; - /** The last timestamp when we sent something */ - protected long lastTimestamp = 0; - /** Current sequence number */ - protected int seqNum = 0; - /** Number of packets sent by this session */ - protected int sentPktCount = 0; - /** Number of octets sent by this session */ - protected int sentOctetCount = 0; - - /** The random seed */ - protected Random random = null; - - /** Session bandwidth in BYTES per second */ - protected int bandwidth = 8000; - - /** By default we do not return packets from strangers in unicast mode */ - protected boolean naiveReception = false; - - /** Should the library attempt frame reconstruction? */ - protected boolean frameReconstruction = true; - - /** Maximum number of packets used for reordering */ - protected int pktBufBehavior = 3; - - /** Participant database */ - protected ParticipantDatabase partDb = new ParticipantDatabase(this); - /** First participant */ - protected Participant firstPart; - /** Handle to application interface for RTP */ - protected RTPAppIntf appIntf = null; - /** Handle to application interface for RTCP (optional) */ - protected RTCPAppIntf rtcpAppIntf = null; - /** Handle to application interface for AVPF, RFC 4585 (optional) */ - protected RTCPAVPFIntf rtcpAVPFIntf = null; - /** Handle to application interface for debugging */ - protected DebugAppIntf debugAppIntf = null; - - /** The RTCP session associated with this RTP Session */ - protected RTCPSession rtcpSession = null; - /** The thread for receiving RTP packets */ - protected RTPReceiverThread recvThrd = null; - /** The thread for invoking callbacks for RTP packets */ - protected AppCallerThread appCallerThrd = null; - - /** Lock to protect the packet buffers */ - final protected Lock pktBufLock = new ReentrantLock(); - /** Condition variable, to tell the */ - final protected Condition pktBufDataReady = pktBufLock.newCondition(); - - /** Enough is enough, set to true when you want to quit. */ - protected boolean endSession = false; - /** Only one registered application, please */ - protected boolean registered = false; - /** We're busy resolving a SSRC conflict, please try again later */ - protected boolean conflict = false; - /** Number of conflicts observed, exessive number suggests loop in network */ - protected int conflictCount = 0; - - /** SDES CNAME */ - protected String cname = null; - /** SDES The participant's real name */ - public String name = null; - /** SDES The participant's email */ - public String email = null; - /** SDES The participant's phone number */ - public String phone = null; - /** SDES The participant's location */ - public String loc = null; - /** SDES The tool the participants is using */ - public String tool = null; - /** SDES A note */ - public String note = null; - /** SDES A priv string, loosely defined */ - public String priv = null; - - // RFC 4585 stuff. This should live on RTCPSession, but we need to have this - // infromation ready by the time the RTCP Session starts - // 0 = RFC 3550 , -1 = ACK , 1 = Immediate feedback, 2 = Early RTCP, - protected int rtcpMode = 0; - protected int fbEarlyThreshold = -1; // group size, immediate -> early - // transition point - protected int fbRegularThreshold = -1; // group size, early -> regular - // transition point - protected int minInterval = 5000; // minimum interval - protected int fbMaxDelay = 1000; // how long the information is useful - // RTCP bandwidth - protected int rtcpBandwidth = -1; - - /** - * Returns an instance of a unicast RTP session. Following this you - * should adjust any settings and then register your application. - * - * The sockets should have external ip addresses, else your CNAME - * automatically generated CNAMe will be bad. - * - * @param rtpSocket - * UDP socket to receive RTP communication on - * @param rtcpSocket - * UDP socket to receive RTCP communication on, null if none. - */ - public RTPSession(DatagramSocket rtpSocket, DatagramSocket rtcpSocket) { - mcSession = false; - rtpSock = rtpSocket; - this.generateCNAME(); - this.generateSsrc(); - this.rtcpSession = new RTCPSession(this, rtcpSocket); - // The sockets are not always imediately available? - try { - Thread.sleep(1); - } catch (InterruptedException e) { - System.out.println("RTPSession sleep failed"); - } - } - - /** - * Returns an instance of a multicast RTP session. Following this you - * should register your application. - * - * The sockets should have external ip addresses, else your CNAME - * automatically generated CNAMe will be bad. - * - * @param rtpSock - * a multicast socket to receive RTP communication on - * @param rtcpSock - * a multicast socket to receive RTP communication on - * @param multicastGroup - * the multicast group that we want to communicate with. - */ - public RTPSession(MulticastSocket rtpSock, MulticastSocket rtcpSock, - InetAddress multicastGroup) throws Exception { - mcSession = true; - rtpMCSock = rtpSock; - mcGroup = multicastGroup; - rtpMCSock.joinGroup(mcGroup); - rtcpSock.joinGroup(mcGroup); - this.generateCNAME(); - this.generateSsrc(); - this.rtcpSession = new RTCPSession(this, rtcpSock, mcGroup); - - // The sockets are not always imediately available? - try { - Thread.sleep(1); - } catch (InterruptedException e) { - System.out.println("RTPSession sleep failed"); - } - } - - /** - * Registers an application (RTPAppIntf) with the RTP session. The session - * will call receiveData() on the supplied instance whenever data has been - * received. - * - * Following this you should set the payload type and add participants to - * the session. - * - * @param rtpApp - * an object that implements the RTPAppIntf-interface - * @param rtcpApp - * an object that implements the RTCPAppIntf-interface (optional) - * @return -1 if this RTPSession-instance already has an application - * registered. - */ - public int RTPSessionRegister(RTPAppIntf rtpApp, RTCPAppIntf rtcpApp, - DebugAppIntf debugApp) { - if (registered) { - System.out - .println("RTPSessionRegister(): Can\'t register another application!"); - return -1; - } else { - - registered = true; - generateSeqNum(); - if (RTPSession.rtpDebugLevel > 0) { - System.out.println("-> RTPSessionRegister"); - } - this.appIntf = rtpApp; - this.rtcpAppIntf = rtcpApp; - this.debugAppIntf = debugApp; - - recvThrd = new RTPReceiverThread(this); - appCallerThrd = new AppCallerThread(this, rtpApp); - //recvThrd.start(); - //appCallerThrd.start(); - //rtcpSession.start(); - return 0; - } - } - - public AppCallerThread getAppCallerThrd() { - return appCallerThrd; - } - - public RTPReceiverThread getRTPRecvThrd() { - return recvThrd; - } - - /** - * Send data to all participants registered as receivers, using the current - * timeStamp, dynamic sequence number and the current payload type specified - * for the session. - * - * @param buf - * A buffer of bytes, less than 1496 bytes - * @return null if there was a problem, {RTP Timestamp, Sequence number} - * otherwise - */ - public long[] sendData(byte[] buf) { - byte[][] tmp = { buf }; - long[][] ret = this.sendData(tmp, null, null, -1, null); - - if (ret != null) - return ret[0]; - - return null; - } - - /** - * Send data to all participants registered as receivers, using the - * specified timeStamp, sequence number and the current payload type - * specified for the session. - * - * @param buf - * A buffer of bytes, less than 1496 bytes - * @param rtpTimestamp - * the RTP timestamp to be used in the packet - * @param seqNum - * the sequence number to be used in the packet - * @return null if there was a problem, {RTP Timestamp, Sequence number} - * otherwise - */ - public long[] sendData(byte[] buf, long rtpTimestamp, long seqNum) { - byte[][] tmp = { buf }; - long[][] ret = this.sendData(tmp, null, null, -1, null); - - if (ret != null) - return ret[0]; - - return null; - } - - /** - * Send data to all participants registered as receivers, using the current - * timeStamp and payload type. The RTP timestamp will be the same for all - * the packets. - * - * @param buffers - * A buffer of bytes, should not bed padded and less than 1500 - * bytes on most networks. - * @param csrcArray - * an array with the SSRCs of contributing sources - * @param markers - * An array indicating what packets should be marked. Rarely - * anything but the first one - * @param rtpTimestamp - * The RTP timestamp to be applied to all packets - * @param seqNumbers - * An array with the sequence number associated with each byte[] - * @return null if there was a problem sending the packets, 2-dim array with - * {RTP Timestamp, Sequence number} - */ - public long[][] sendData(byte[][] buffers, long[] csrcArray, - boolean[] markers, long rtpTimestamp, long[] seqNumbers) { - if (RTPSession.rtpDebugLevel > 5) { - System.out.println("-> RTPSession.sendData(byte[])"); - } - - // Same RTP timestamp for all - if (rtpTimestamp < 0) - rtpTimestamp = System.currentTimeMillis(); - - // Return values - long[][] ret = new long[buffers.length][2]; - - for (int i = 0; i < buffers.length; i++) { - byte[] buf = buffers[i]; - - boolean marker = false; - if (markers != null) - marker = markers[i]; - - if (buf.length > 1500) { - System.out - .println("RTPSession.sendData() called with buffer exceeding 1500 bytes (" - + buf.length + ")"); - } - - // Get the return values - ret[i][0] = rtpTimestamp; - if (seqNumbers == null) { - ret[i][1] = getNextSeqNum(); - } else { - ret[i][1] = seqNumbers[i]; - } - // Create a new RTP Packet - RtpPkt pkt = RtpPktPool.getInstance().borrowPkt(); - pkt.initPacket(rtpTimestamp, this.ssrc, (int) ret[i][1], - this.payloadType, buf); - - if (csrcArray != null) - pkt.setCsrcs(csrcArray); - - pkt.setMarked(marker); - - // Creates a raw packet - byte[] pktBytes = pkt.encode(); - - // System.out.println(Integer.toString(StaticProcs.bytesToUIntInt(pktBytes, - // 2))); - - // Pre-flight check, are resolving an SSRC conflict? - if (this.conflict) { - System.out - .println("RTPSession.sendData() called while trying to resolve conflict."); - return null; - } - - if (this.mcSession) { - DatagramPacket packet = null; - - try { - packet = new DatagramPacket(pktBytes, pktBytes.length, - this.mcGroup, this.rtpMCSock.getPort()); - } catch (Exception e) { - System.out - .println("RTPSession.sendData() packet creation failed."); - e.printStackTrace(); - return null; - } - - try { - rtpMCSock.send(packet); - // Debug - if (this.debugAppIntf != null) { - this.debugAppIntf.packetSent(1, - (InetSocketAddress) packet.getSocketAddress(), - new String("Sent multicast RTP packet of size " - + packet.getLength() - + " to " - + packet.getSocketAddress().toString() - + " via " - + rtpMCSock.getLocalSocketAddress() - .toString())); - } - } catch (Exception e) { - System.out - .println("RTPSession.sendData() multicast failed."); - e.printStackTrace(); - return null; - } - - } else { - // Loop over recipients - Iterator iter = partDb.getUnicastReceivers(); - while (iter.hasNext()) { - InetSocketAddress receiver = iter.next().rtpAddress; - DatagramPacket packet = null; - - if (RTPSession.rtpDebugLevel > 15) { - System.out.println(" Sending to " - + receiver.toString()); - } - - try { - packet = new DatagramPacket(pktBytes, pktBytes.length, - receiver); - } catch (Exception e) { - System.out - .println("RTPSession.sendData() packet creation failed."); - e.printStackTrace(); - return null; - } - - // Actually send the packet - try { - rtpSock.send(packet); - // Debug - if (this.debugAppIntf != null) { - this.debugAppIntf - .packetSent( - 0, - (InetSocketAddress) packet - .getSocketAddress(), - new String( - "Sent unicast RTP packet of size " - + packet - .getLength() - + " to " - + packet - .getSocketAddress() - .toString() - + " via " - + rtpSock - .getLocalSocketAddress() - .toString())); - } - } catch (Exception e) { - System.out - .println("RTPSession.sendData() unicast failed."); - e.printStackTrace(); - return null; - } - } - } - - // Update our stats - this.sentPktCount++; - this.sentOctetCount++; - - if (RTPSession.rtpDebugLevel > 5) { - System.out.println("<- RTPSession.sendData(byte[]) " - + pkt.getSeqNumber()); - } - } - - return ret; - } - - public void sendData(DatagramPacket packet, RtpPkt pkt) { - if (RTPSession.rtpDebugLevel > 5) { - System.out.println("-> RTPSession.sendData(byte[])"); - } - - pkt.setTimeStamp(System.currentTimeMillis()); - pkt.setSsrc(ssrc); - pkt.setSeqNumber(getNextSeqNum()); - - // Creates a raw packet - pkt.writeHeader(); - - // Pre-flight check, are resolving an SSRC conflict? - if (this.conflict) { - System.out - .println("RTPSession.sendData() called while trying to resolve conflict."); - return; - } - - if (this.mcSession) { - try { - packet.setPort(this.rtpMCSock.getPort()); - packet.setAddress(this.mcGroup); - } catch (Exception e) { - System.out - .println("RTPSession.sendData() packet creation failed."); - e.printStackTrace(); - return; - } - try { - rtpMCSock.send(packet); - // Debug - if (this.debugAppIntf != null) { - this.debugAppIntf.packetSent(1, - (InetSocketAddress) packet.getSocketAddress(), - new String("Sent multicast RTP packet of size " - + packet.getLength() - + " to " - + packet.getSocketAddress().toString() - + " via " - + rtpMCSock.getLocalSocketAddress() - .toString())); - } - } catch (Exception e) { - System.out - .println("RTPSession.sendData() multicast failed."); - e.printStackTrace(); - return; - } - - } else { - try { - packet.setSocketAddress(firstPart.rtpAddress); - } catch (Exception e) { - System.out - .println("RTPSession.sendData() packet creation failed."); - e.printStackTrace(); - return; - } - - // Actually send the packet - try { - - rtpSock.send(packet); - //Log.d("RTP", "packet"); - // Debug - if (this.debugAppIntf != null) { - this.debugAppIntf - .packetSent( - 0, - (InetSocketAddress) packet - .getSocketAddress(), - new String( - "Sent unicast RTP packet of size " - + packet - .getLength() - + " to " - + packet - .getSocketAddress() - .toString() - + " via " - + rtpSock - .getLocalSocketAddress() - .toString())); - } - } catch (Exception e) { - System.out - .println("RTPSession.sendData() unicast failed."); - e.printStackTrace(); - return; - } - } - - // Update our stats - this.sentPktCount++; - this.sentOctetCount++; - if (RTPSession.rtpDebugLevel > 5) { - System.out.println("<- RTPSession.sendData(byte[]) " - + pkt.getSeqNumber()); - } - } - - /** - * Send RTCP App packet to receiver specified by ssrc - * - * - * - * Return values: 0 okay -1 no RTCP session established -2 name is not - * byte[4]; -3 data is not byte[x], where x = 4*y for syme y -4 type is not - * a 5 bit unsigned integer - * - * Note that a return value of 0 does not guarantee delivery. The - * participant must also exist in the participant database, otherwise the - * message will eventually be deleted. - * - * @param ssrc - * of the participant you want to reach - * @param type - * the RTCP App packet subtype, default 0 - * @param name - * the ASCII (in byte[4]) representation - * @param data - * the data itself - * @return 0 if okay, negative value otherwise (see above) - */ - - public int sendRTCPAppPacket(long ssrc, int type, byte[] name, byte[] data) { - if (this.rtcpSession == null) - return -1; - - if (name.length != 4) - return -2; - - if (data.length % 4 != 0) - return -3; - - if (type > 63 || type < 0) - return -4; - - RtcpPktAPP pkt = new RtcpPktAPP(ssrc, type, name, data); - this.rtcpSession.addToAppQueue(ssrc, pkt); - - return 0; - } - - /** - * Add a participant object to the participant database. - * - * If packets have already been received from this user, we will try to - * update the automatically inserted participant with the information - * provided here. - * - * @param p - * A participant. - */ - public int addParticipant(Participant p) { - // For now we make all participants added this way persistent - firstPart = p; - p.unexpected = false; - return this.partDb.addParticipant(0, p); - } - - /** - * Remove a participant from the database. All buffered packets will be - * destroyed. - * - * @param p - * A participant. - */ - public void removeParticipant(Participant p) { - partDb.removeParticipant(p); - } - - public Iterator getUnicastReceivers() { - return partDb.getUnicastReceivers(); - } - - public Enumeration getParticipants() { - return partDb.getParticipants(); - } - - /** - * End the RTP Session. This will halt all threads and send bye-messages to - * other participants. - * - * RTCP related threads may require several seconds to wake up and - * terminate. - */ - public void endSession() { - this.endSession = true; - - // No more RTP packets, please - if (this.mcSession) { - this.rtpMCSock.close(); - } else { - this.rtpSock.close(); - } - - // Signal the thread that pushes data to application - this.pktBufLock.lock(); - try { - this.pktBufDataReady.signalAll(); - } finally { - this.pktBufLock.unlock(); - } - // Interrupt what may be sleeping - //this.rtcpSession.senderThrd.interrupt(); - - // Give things a chance to cool down. - try { - Thread.sleep(50); - } catch (Exception e) { - } - ; - - this.appCallerThrd.interrupt(); - - // Give things a chance to cool down. - try { - Thread.sleep(50); - } catch (Exception e) { - } - ; - - if (this.rtcpSession != null) { - // No more RTP packets, please - if (this.mcSession) { - this.rtcpSession.rtcpMCSock.close(); - } else { - this.rtcpSession.rtcpSock.close(); - } - } - DatagramPool.removeInstance(); - PktBufNodePool.removeInstance(); - DataFramePool.removeInstance(); - RtpPktPool.removeInstance(); - } - - /** - * Check whether this session is ending. - * - * @return true if session and associated threads are terminating. - */ - boolean isEnding() { - return this.endSession; - } - - /** - * Overrides CNAME, used for outgoing RTCP packets. - * - * @param cname - * a string, e.g. username@hostname. Must be unique for session. - */ - public void CNAME(String cname) { - this.cname = cname; - } - - /** - * Get the current CNAME, used for outgoing SDES packets - */ - public String CNAME() { - return this.cname; - } - - public long getSsrc() { - return this.ssrc; - } - - private void generateCNAME() { - String hostname; - - if (this.mcSession) { - hostname = this.rtpMCSock.getLocalAddress().getCanonicalHostName(); - } else { - hostname = this.rtpSock.getLocalAddress().getCanonicalHostName(); - } - - // if(hostname.equals("0.0.0.0") && System.getenv("HOSTNAME") != null) { - // hostname = System.getenv("HOSTNAME"); - // } - - cname = System.getProperty("user.name") + "@" + hostname; - } - - /** - * Change the RTP socket of the session. Peers must be notified through SIP - * or other signalling protocol. Only valid if this is a unicast session to - * begin with. - * - * @param newSock - * integer for new port number, check it is free first. - */ - public int updateRTPSock(DatagramSocket newSock) { - if (!mcSession) { - rtpSock = newSock; - return 0; - } else { - System.out.println("Can't switch from multicast to unicast."); - return -1; - } - } - - /** - * Change the RTCP socket of the session. Peers must be notified through SIP - * or other signalling protocol. Only valid if this is a unicast session to - * begin with. - * - * @param newSock - * the new unicast socket for RTP communication. - */ - public int updateRTCPSock(DatagramSocket newSock) { - if (!mcSession) { - this.rtcpSession.rtcpSock = newSock; - return 0; - } else { - System.out.println("Can't switch from multicast to unicast."); - return -1; - } - } - - /** - * Change the RTP multicast socket of the session. Peers must be notified - * through SIP or other signalling protocol. Only valid if this is a - * multicast session to begin with. - * - * @param newSock - * the new multicast socket for RTP communication. - */ - public int updateRTPSock(MulticastSocket newSock) { - if (mcSession) { - this.rtpMCSock = newSock; - return 0; - } else { - System.out.println("Can't switch from unicast to multicast."); - return -1; - } - } - - /** - * Change the RTCP multicast socket of the session. Peers must be notified - * through SIP or other signalling protocol. Only valid if this is a - * multicast session to begin with. - * - * @param newSock - * the new multicast socket for RTCP communication. - */ - public int updateRTCPSock(MulticastSocket newSock) { - if (mcSession) { - this.rtcpSession.rtcpMCSock = newSock; - return 0; - } else { - System.out.println("Can't switch from unicast to multicast."); - return -1; - } - } - - /** - * Update the payload type used for the session. It is represented as a 7 - * bit integer, whose meaning must be negotiated elsewhere (see IETF RFCs 3550 and 3551) - * - * @param payloadT - * an integer representing the payload type of any subsequent - * packets that are sent. - */ - public int payloadType(int payloadT) { - if (payloadT > 128 || payloadT < 0) { - return -1; - } else { - this.payloadType = payloadT; - return this.payloadType; - } - } - - /** - * Get the payload type that is currently used for outgoing RTP packets. - * - * @return payload type as integer - */ - public int payloadType() { - return this.payloadType; - } - - /** - * Should packets from unknown participants be returned to the application? - * This can be dangerous. - * - * @param doAccept - * packets from participants not added by the application. - */ - public void naivePktReception(boolean doAccept) { - naiveReception = doAccept; - } - - /** - * Are packets from unknown participants returned to the application? - * - * @return whether we accept packets from participants not added by the - * application. - */ - public boolean naivePktReception() { - return naiveReception; - } - - /** - * Set the number of RTP packets that should be buffered when a packet is - * missing or received out of order. Setting this number high increases the - * chance of correctly reordering packets, but increases latency when a - * packet is dropped by the network. - * - * Packets that arrive in order are not affected, they are passed straight - * to the application. - * - * The maximum delay is numberofPackets * packet rate , where the packet - * rate depends on the codec and profile used by the sender. - * - * Valid values: >0 - The maximum number of packets (based on RTP Timestamp) - * that may accumulate 0 - All valid packets received in order will be given - * to the application -1 - All valid packets will be given to the - * application - * - * @param behavior - * the be - * @return the behavior set, unchanged in the case of a erroneous value - */ - public int packetBufferBehavior(int behavior) { - if (behavior > -2) { - this.pktBufBehavior = behavior; - // Signal the thread that pushes data to application - this.pktBufLock.lock(); - try { - this.pktBufDataReady.signalAll(); - } finally { - this.pktBufLock.unlock(); - } - return this.pktBufBehavior; - } else { - return this.pktBufBehavior; - } - } - - /** - * The number of RTP packets that should be buffered when a packet is - * missing or received out of order. A high number increases the chance of - * correctly reordering packets, but increases latency when a packet is - * dropped by the network. - * - * A negative value disables the buffering, out of order packets will simply - * be dropped. - * - * @return the maximum number of packets that can accumulate before the - * first is returned - */ - public int packetBufferBehavior() { - return this.pktBufBehavior; - } - - /** - * Set whether the stack should operate in RFC 4585 mode. - * - * This will automatically call adjustPacketBufferBehavior(-1), i.e. disable - * all RTP packet buffering in jlibrtp, and disable frame reconstruction - * - * @param rtcpAVPFIntf - * the in - */ - public int registerAVPFIntf(RTCPAVPFIntf rtcpAVPFIntf, int maxDelay, - int earlyThreshold, int regularThreshold) { - if (this.rtcpSession != null) { - this.packetBufferBehavior(-1); - this.frameReconstruction = false; - this.rtcpAVPFIntf = rtcpAVPFIntf; - this.fbEarlyThreshold = earlyThreshold; - this.fbRegularThreshold = regularThreshold; - return 0; - } else { - return -1; - } - } - - /** - * Unregisters the RTCP AVPF interface, thereby going from RFC 4585 mode to - * RFC 3550 - * - * You still have to adjust packetBufferBehavior() and frameReconstruction. - * - */ - public void unregisterAVPFIntf() { - this.fbEarlyThreshold = -1; - this.fbRegularThreshold = -1; - this.rtcpAVPFIntf = null; - } - - /** - * Enable / disable frame reconstruction in the packet buffers. This is only - * relevant if getPacketBufferBehavior > 0; - * - * Default is true. - */ - public void frameReconstruction(boolean toggle) { - this.frameReconstruction = toggle; - } - - /** - * Whether the packet buffer will attempt to reconstruct packet - * automatically. - * - * @return the status - */ - public boolean frameReconstruction() { - return this.frameReconstruction; - } - - /** - * The bandwidth currently allocated to the session, in bytes per second. - * The default is 8000. - * - * This value is not enforced and currently only used to calculate the RTCP - * interval to ensure the control messages do not exceed 5% of the total - * bandwidth described here. - * - * Since the actual value may change a conservative estimate should be used - * to avoid RTCP flooding. - * - * see rtcpBandwidth(void) - * - * @return current bandwidth setting - */ - public int sessionBandwidth() { - return this.bandwidth; - } - - /** - * Set the bandwidth of the session. - * - * See sessionBandwidth(void) for details. - * - * @param bandwidth - * the new value requested, in bytes per second - * @return the actual value set - */ - public int sessionBandwidth(int bandwidth) { - if (bandwidth < 1) { - this.bandwidth = 8000; - } else { - this.bandwidth = bandwidth; - } - return this.bandwidth; - } - - /** - * RFC 3550 dictates that 5% of the total bandwidth, as set by - * sessionBandwidth, should be dedicated to RTCP traffic. This - * - * This should normally not be done, but is permissible in conjunction with - * feedback (RFC 4585) and possibly other profiles. - * - * Also see sessionBandwidth(void) - * - * @return current RTCP bandwidth setting, -1 means not in use - */ - public int rtcpBandwidth() { - return this.rtcpBandwidth; - } - - /** - * Set the RTCP bandwidth, see rtcpBandwidth(void) for details. - * - * This function must be - * - * @param bandwidth - * the new value requested, in bytes per second or -1 to disable - * @return the actual value set - */ - public int rtcpBandwidth(int bandwidth) { - if (bandwidth < -1) { - this.rtcpBandwidth = -1; - } else { - this.rtcpBandwidth = bandwidth; - } - return this.rtcpBandwidth; - } - - /********************************************* Feedback message stuff ***************************************/ - - /** - * Adds a Picture Loss Indication to the feedback queue - * - * @param ssrcMediaSource - * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant - */ - public int fbPictureLossIndication(long ssrcMediaSource) { - int ret = 0; - - if (this.rtcpAVPFIntf == null) - return -1; - - RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource); - pkt.makePictureLossIndication(); - ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt); - if (ret == 0) - this.rtcpSession.wakeSenderThread(ssrcMediaSource); - return ret; - } - - /** - * Adds a Slice Loss Indication to the feedback queue - * - * @param ssrcMediaSource - * @param sliFirst - * macroblock (MB) address of the first lost macroblock - * @param sliNumber - * number of lost macroblocks - * @param sliPictureId - * six least significant bits of the codec-specific identif - * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant - */ - public int fbSlicLossIndication(long ssrcMediaSource, int[] sliFirst, - int[] sliNumber, int[] sliPictureId) { - int ret = 0; - if (this.rtcpAVPFIntf == null) - return -1; - - RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource); - pkt.makeSliceLossIndication(sliFirst, sliNumber, sliPictureId); - - ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt); - if (ret == 0) - this.rtcpSession.wakeSenderThread(ssrcMediaSource); - return ret; - } - - /** - * Adds a Reference Picture Selection Indication to the feedback queue - * - * @param ssrcMediaSource - * @param bitPadding - * number of padded bits at end of bitString - * @param payloadType - * RTP payload type for codec - * @param bitString - * RPSI information as natively defined by the video codec - * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant - */ - public int fbRefPictureSelIndic(long ssrcMediaSource, int bitPadding, - int payloadType, byte[] bitString) { - int ret = 0; - - if (this.rtcpAVPFIntf == null) - return -1; - - RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource); - pkt.makeRefPictureSelIndic(bitPadding, payloadType, bitString); - ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt); - if (ret == 0) - this.rtcpSession.wakeSenderThread(ssrcMediaSource); - return ret; - } - - /** - * Adds a Picture Loss Indication to the feedback queue - * - * @param ssrcMediaSource - * @param bitString - * the original application message - * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant - */ - public int fbAppLayerFeedback(long ssrcMediaSource, byte[] bitString) { - int ret = 0; - - if (this.rtcpAVPFIntf == null) - return -1; - - RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource); - pkt.makeAppLayerFeedback(bitString); - ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt); - if (ret == 0) - this.rtcpSession.wakeSenderThread(ssrcMediaSource); - return ret; - } - - /** - * Adds a RTP Feedback packet to the feedback queue. - * - * These are mostly used for NACKs. - * - * @param ssrcMediaSource - * @param FMT - * the Feedback Message Subtype - * @param PID - * RTP sequence numbers of lost packets - * @param BLP - * bitmask of following lost packets, shared index with PID - * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant - */ - public int fbPictureLossIndication(long ssrcMediaSource, int FMT, - int[] PID, int[] BLP) { - int ret = 0; - - if (this.rtcpAVPFIntf == null) - return -1; - - RtcpPktRTPFB pkt = new RtcpPktRTPFB(this.ssrc, ssrcMediaSource, FMT, - PID, BLP); - ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt); - if (ret == 0) - this.rtcpSession.wakeSenderThread(ssrcMediaSource); - return ret; - } - - /** - * Fetches the next sequence number for RTP packets. - * - * @return the next sequence number - */ - private int getNextSeqNum() { - seqNum++; - // 16 bit number - if (seqNum > 65536) { - seqNum = 0; - } - return seqNum; - } - - /** - * Initializes a random variable - * - */ - private void createRandom() { - this.random = new Random(System.currentTimeMillis() - + Thread.currentThread().getId() - - Thread.currentThread().hashCode() + this.cname.hashCode()); - } - - /** - * Generates a random sequence number - */ - private void generateSeqNum() { - if (this.random == null) - createRandom(); - - seqNum = this.random.nextInt(); - if (seqNum < 0) - seqNum = -seqNum; - while (seqNum > 65535) { - seqNum = seqNum / 10; - } - } - - /** - * Generates a random SSRC - */ - private void generateSsrc() { - if (this.random == null) - createRandom(); - - // Set an SSRC - this.ssrc = this.random.nextInt(); - if (this.ssrc < 0) { - this.ssrc = this.ssrc * -1; - } - } - - /** - * Resolve an SSRC conflict. - * - * Also increments the SSRC conflict counter, after 5 conflicts it is - * assumed there is a loop somewhere and the session will terminate. - * - */ - protected void resolveSsrcConflict() { - System.out - .println("!!!!!!! Beginning SSRC conflict resolution !!!!!!!!!"); - this.conflictCount++; - - if (this.conflictCount < 5) { - // Don't send any more regular packets out until we have this sorted - // out. - this.conflict = true; - - // Send byes - rtcpSession.sendByes(); - - // Calculate the next delay - rtcpSession.calculateDelay(); - - // Generate a new Ssrc for ourselves - generateSsrc(); - - // Get the SDES packets out faster - rtcpSession.initial = true; - - this.conflict = false; - System.out.println("SSRC conflict resolution complete"); - - } else { - System.out - .println("Too many conflicts. There is probably a loop in the network."); - this.endSession(); - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPkt.java --- a/src/jlibrtp/RtcpPkt.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.InetAddress; - -/** - * Common RTCP packet headers. - * - * @author Arne Kepp - */ -public class RtcpPkt { - /** Whether a problem has been encountered during parsing */ - protected int problem = 0; - /** The version, always 2, 2 bits */ - protected int version = 2; - /** Padding , 1 bit */ - protected int padding = 0; - /** Number of items, e.g. receiver report blocks. Usage may vary. 5 bits */ - protected int itemCount = 0; - /** The type of RTCP packet, 8 bits */ - protected int packetType = -1; - /** The length of the RTCP packet, in 32 bit blocks minus 1. 16 bits */ - protected int length = -1; - /** The ssrc that sent this, usually dictated by RTP Session */ - protected long ssrc = -1; - - /** Contains the actual data (eventually) */ - protected byte[] rawPkt = null; - - /** Only used for feedback messages: Time message was generated */ - protected long time = -1; - /** Only used for feedback message: Whether this packet was received */ - protected boolean received = false; - - /** - * Parses the common header of an RTCP packet - * - * @param start - * where in this.rawPkt the headers start - * @return true if parsing succeeded and header cheks - */ - protected boolean parseHeaders(int start) { - version = ((rawPkt[start + 0] & 0xC0) >>> 6); - padding = ((rawPkt[start + 0] & 0x20) >>> 5); - itemCount = (rawPkt[start + 0] & 0x1F); - packetType = (int) rawPkt[start + 1]; - if (packetType < 0) { - packetType += 256; - } - length = StaticProcs.bytesToUIntInt(rawPkt, start + 2); - - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" <-> RtcpPkt.parseHeaders() version:" + version - + " padding:" + padding + " itemCount:" + itemCount - + " packetType:" + packetType + " length:" + length); - } - - if (packetType > 207 || packetType < 200) - System.out - .println("RtcpPkt.parseHeaders problem discovered, packetType " - + packetType); - - if (version == 2 && length < 65536) { - return true; - } else { - System.out - .println("RtcpPkt.parseHeaders() failed header checks, check size and version"); - this.problem = -1; - return false; - } - } - - /** - * Writes the common header of RTCP packets. The values should be filled in - * when the packet is initiliazed and this function called at the very end - * of .encode() - */ - protected void writeHeaders() { - byte aByte = 0; - aByte |= (version << 6); - aByte |= (padding << 5); - aByte |= (itemCount); - rawPkt[0] = aByte; - aByte = 0; - aByte |= packetType; - rawPkt[1] = aByte; - if (rawPkt.length % 4 != 0) - System.out - .println("!!!! RtcpPkt.writeHeaders() rawPkt was not a multiple of 32 bits / 4 octets!"); - StaticProcs.uIntIntToByteWord((rawPkt.length / 4) - 1, rawPkt, 2); - } - - /** - * This is just a dummy to make Eclipse complain less. - */ - protected void encode() { - System.out.println("RtcpPkt.encode() should never be invoked!! " - + this.packetType); - } - - /** - * Check whether this packet came from the source we expected. - * - * Not currently used! - * - * @param adr - * address that packet came from - * @param partDb - * the participant database for the session - * @return true if this packet came from the expected source - */ - protected boolean check(InetAddress adr, ParticipantDatabase partDb) { - // Multicast -> We have to be naive - if (partDb.rtpSession.mcSession - && adr.equals(partDb.rtpSession.mcGroup)) - return true; - - // See whether this participant is known - Participant part = partDb.getParticipant(this.ssrc); - if (part != null && part.rtcpAddress.getAddress().equals(adr)) - return true; - - // If not, we should look for someone without SSRC with his ip-address? - return false; - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktAPP.java --- a/src/jlibrtp/RtcpPktAPP.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * Application specific RTCP packets - * - * @author Arne Kepp - */ -public class RtcpPktAPP extends RtcpPkt { - /** Name of packet, 4 bytes ASCII */ - protected byte[] pktName = null; - /** Data of packet */ - protected byte[] pktData = null; - - /** - * Constructor for a new Application RTCP packet - * - * @param ssrc - * the SSRC of the sender, presumably taken from RTPSession - * @param subtype - * the subtype of packet, application specific - * @param pktName - * byte[4] representing ASCII name of packet - * @param pktData - * the byte[4x] data that represents the message itself - */ - protected RtcpPktAPP(long ssrc, int subtype, byte[] pktName, byte[] pktData) { - // Fetch all the right stuff from the database - super.ssrc = ssrc; - super.packetType = 204; - super.itemCount = subtype; - this.pktName = pktName; - this.pktData = pktData; - } - - /** - * Constructor that parses a received Application RTCP packet - * - * @param aRawPkt - * the raw packet containing the date - * @param start - * where in the raw packet this packet starts - */ - protected RtcpPktAPP(byte[] aRawPkt, int start) { - super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4); - super.rawPkt = aRawPkt; - - if (!super.parseHeaders(start) || packetType != 204) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktAPP.parseHeaders() etc. problem"); - } - super.problem = -204; - } else { - // System.out.println("super.length: " + super.length); - if (super.length > 1) { - pktName = new byte[4]; - System.arraycopy(aRawPkt, 8, pktName, 0, 4); - } - if (super.length > 2) { - pktData = new byte[(super.length + 1) * 4 - 12]; - System.arraycopy(aRawPkt, 12, pktData, 0, pktData.length); - } - } - } - - /** - * Encode the packet into a byte[], saved in .rawPkt - * - * CompRtcpPkt will call this automatically - */ - protected void encode() { - super.rawPkt = new byte[12 + this.pktData.length]; - byte[] tmp = StaticProcs.uIntLongToByteWord(super.ssrc); - System.arraycopy(tmp, 0, super.rawPkt, 4, 4); - System.arraycopy(this.pktName, 0, super.rawPkt, 8, 4); - System - .arraycopy(this.pktData, 0, super.rawPkt, 12, - this.pktData.length); - writeHeaders(); - // System.out.println("ENCODE: " + super.length + " " + rawPkt.length + - // " " + pktData.length); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktBYE.java --- a/src/jlibrtp/RtcpPktBYE.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * RTCP packets for sending Bye messages - * - * @author Arne Kepp - */ -public class RtcpPktBYE extends RtcpPkt { - /** SSRCs saying bye, 32xn bits, n<16 */ - protected long[] ssrcArray = null; - /** Optional reason */ - protected byte[] reason = null; - - protected RtcpPktBYE(long[] ssrcs, byte[] aReason) { - super.packetType = 203; - // Fetch all the right stuff from the database - reason = aReason; - ssrcArray = ssrcs; - if (ssrcs.length < 1) { - System.out - .println("RtcpBYE.RtcpPktBYE(long[] ssrcs, byte[] aReason) requires at least one SSRC!"); - } - } - - protected RtcpPktBYE(byte[] aRawPkt, int start) { - rawPkt = aRawPkt; - if (!super.parseHeaders(start) || packetType != 203) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktBYE.parseHeaders() etc. problem"); - } - super.problem = -203; - } else { - ssrcArray = new long[super.itemCount]; - - for (int i = 0; i < super.itemCount; i++) { - ssrcArray[i] = StaticProcs.bytesToUIntLong(aRawPkt, start - + (i + 1) * 4); - } - if (super.length > (super.itemCount + 1)) { - int reasonLength = (int) aRawPkt[start + (super.itemCount + 1) - * 4]; - // System.out.println("super.itemCount:"+super.itemCount+" reasonLength:"+reasonLength+" start:"+(super.itemCount*4 - // + 4 + 1)); - reason = new byte[reasonLength]; - System.arraycopy(aRawPkt, - start + (super.itemCount + 1) * 4 + 1, reason, 0, - reasonLength); - // System.out.println("test:" + new String(reason)); - } - } - } - - protected void encode() { - itemCount = ssrcArray.length; - length = 4 * ssrcArray.length; - - if (reason != null) { - length += (reason.length + 1) / 4; - if ((reason.length + 1) % 4 != 0) { - length += 1; - } - } - rawPkt = new byte[length * 4 + 4]; - - int i; - byte[] someBytes; - - // SSRCs - for (i = 0; i < ssrcArray.length; i++) { - someBytes = StaticProcs.uIntLongToByteWord(ssrcArray[i]); - System.arraycopy(someBytes, 0, rawPkt, 4 + 4 * i, 4); - } - - // Reason for leaving - if (reason != null) { - // System.out.println("Writing to:"+(4+4*ssrcArray.length)+ - // " reason.length:"+reason.length ); - rawPkt[(4 + 4 * ssrcArray.length)] = (byte) reason.length; - System.arraycopy(reason, 0, rawPkt, 4 + 4 * i + 1, reason.length); - } - super.writeHeaders(); - } - - public void debugPrint() { - System.out.println("RtcpPktBYE.debugPrint() "); - if (ssrcArray != null) { - for (int i = 0; i < ssrcArray.length; i++) { - long anSsrc = ssrcArray[i]; - System.out.println(" ssrc: " + anSsrc); - } - } - if (reason != null) { - System.out.println(" Reason: " + new String(reason)); - } - } -} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktPSFB.java --- a/src/jlibrtp/RtcpPktPSFB.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,411 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * RTCP packets for Payload-Specific Feedback Messages - * - * @author Arne Kepp - */ -public class RtcpPktPSFB extends RtcpPkt { - /** If this packet was for a different SSRC */ - protected boolean notRelevant = false; - /** Parent RTP Session */ - private RTPSession rtpSession; - /** SSRC we are sending feeback to */ - protected long ssrcMediaSource = -1; - - /** SLI macroblock (MB) address of the first lost macroblock number */ - protected int[] sliFirst; - /** SLI number of lost macroblocks */ - protected int[] sliNumber; - /** SLI six least significant bits of the codec-specific identifier */ - protected int[] sliPictureId; - - // Picture loss indication - /** RPSI number of padded bits at end of bitString */ - protected int rpsiPadding = -1; - /** RPSI payloadType RTP payload type */ - protected int rpsiPayloadType = -1; - /** RPSI information as natively defined by the video codec */ - protected byte[] rpsiBitString; - - /** Application Layer Feedback Message */ - protected byte[] alfBitString; - - /** - * Generic constructor, then call make - * - * @param ssrcPacketSender - * @param ssrcMediaSource - */ - protected RtcpPktPSFB(long ssrcPacketSender, long ssrcMediaSource) { - super.ssrc = ssrcPacketSender; - this.ssrcMediaSource = ssrcMediaSource; - super.packetType = 206; // PSFB - } - - /** - * Make this packet a Picture loss indication - */ - protected void makePictureLossIndication() { - super.itemCount = 1; // FMT - } - - /** - * Make this packet a Slice Loss Indication - * - * @param sliFirst - * macroblock (MB) address of the first lost macroblock - * @param sliNumber - * number of lost macroblocks - * @param sliPictureId - * six least significant bits of the codec-specific identifier - */ - protected void makeSliceLossIndication(int[] sliFirst, int[] sliNumber, - int[] sliPictureId) { - super.itemCount = 2; // FMT - this.sliFirst = sliFirst; - this.sliNumber = sliNumber; - this.sliPictureId = sliPictureId; - } - - /** - * Make this packet a Reference Picture Selection Indication - * - * @param bitPadding - * number of padded bits at end of bitString - * @param payloadType - * RTP payload type for codec - * @param bitString - * RPSI information as natively defined by the video codec - */ - protected void makeRefPictureSelIndic(int bitPadding, int payloadType, - byte[] bitString) { - super.itemCount = 3; // FMT - this.rpsiPadding = bitPadding; - this.rpsiPayloadType = payloadType; - this.rpsiBitString = bitString; - } - - /** - * Make this packet an Application specific feedback message - * - * @param bitString - * the original application message - */ - protected void makeAppLayerFeedback(byte[] bitString) { - super.itemCount = 15; // FMT - this.alfBitString = bitString; - } - - /** - * Constructor that parses a raw packet to retrieve information - * - * @param aRawPkt - * the raw packet to be parsed - * @param start - * the start of the packet, in bytes - * @param rtpSession - * the session on which the callback interface resides - */ - protected RtcpPktPSFB(byte[] aRawPkt, int start, RTPSession rtpSession) { - if (RTPSession.rtpDebugLevel > 8) { - System.out.println(" -> RtcpPktPSFB(byte[], int start)"); - } - this.rtpSession = rtpSession; - - rawPkt = aRawPkt; - - if (!super.parseHeaders(start) || packetType != 206 || super.length < 2) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktRTPFB.parseHeaders() etc. problem"); - } - super.problem = -206; - } else { - // FMT = super.itemCount; - ssrcMediaSource = StaticProcs.bytesToUIntLong(aRawPkt, 8 + start); - - if (ssrcMediaSource == rtpSession.ssrc) { - super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4 + start); - - switch (super.itemCount) { - case 1: // Picture Loss Indication - decPictureLossIndic(); - break; - case 2: // Slice Loss Indication - decSliceLossIndic(aRawPkt, start + 12); - break; - case 3: // Reference Picture Selection Indication - decRefPictureSelIndic(aRawPkt, start + 12); - break; - case 15: // Application Layer Feedback Messages - decAppLayerFB(aRawPkt, start + 12); - break; - default: - System.out - .println("!!!! RtcpPktPSFB(byte[], int start) unexpected FMT " - + super.itemCount); - } - } else { - this.notRelevant = true; - } - } - if (RTPSession.rtpDebugLevel > 8) { - System.out.println(" <- RtcpPktPSFB()"); - } - } - - /** - * Decode Picture Loss indication - * - */ - private void decPictureLossIndic() { - if (this.rtpSession.rtcpAVPFIntf != null) { - this.rtpSession.rtcpAVPFIntf.PSFBPktPictureLossReceived(super.ssrc); - } - } - - /** - * Decode Slice Loss Indication - * - * @param aRawPkt - * @param start - */ - private void decSliceLossIndic(byte[] aRawPkt, int start) { - // 13 bit off-boundary numbers? That's rather cruel - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | First | Number | PictureID | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - int count = super.length - 2; - - sliFirst = new int[count]; - sliNumber = new int[count]; - sliPictureId = new int[count]; - - // Loop over the FCI lines - for (int i = 0; i < count; i++) { - sliFirst[i] = StaticProcs.bytesToUIntInt(aRawPkt, start) >> 3; - sliNumber[i] = (int) (StaticProcs.bytesToUIntInt(aRawPkt, start) & 0x0007FFC0) >> 6; - sliPictureId[i] = (StaticProcs.bytesToUIntInt(aRawPkt, start + 2) & 0x003F); - start += 4; - } - - if (this.rtpSession.rtcpAVPFIntf != null) { - this.rtpSession.rtcpAVPFIntf.PSFBPktSliceLossIndic(super.ssrc, - sliFirst, sliNumber, sliPictureId); - } - } - - /** - * Decode Reference Picture Selection Indication - * - * @param aRawPkt - * @param start - */ - private void decRefPictureSelIndic(byte[] aRawPkt, int start) { - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | PB |0| Payload Type| Native RPSI bit string | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | defined per codec ... | Padding (0) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - rpsiPadding = aRawPkt[start]; - - if (rpsiPadding > 32) { - System.out - .println("!!!! RtcpPktPSFB.decRefPictureSelcIndic paddingBits: " - + rpsiPadding); - } - - rpsiPayloadType = (int) rawPkt[start]; - if (rpsiPayloadType < 0) { - System.out - .println("!!!! RtcpPktPSFB.decRefPictureSelcIndic 8th bit not zero: " - + rpsiPayloadType); - } - - rpsiBitString = new byte[(super.length - 2) * 4 - 2]; - System.arraycopy(aRawPkt, start + 2, rpsiBitString, 0, - rpsiBitString.length); - - if (this.rtpSession.rtcpAVPFIntf != null) { - this.rtpSession.rtcpAVPFIntf.PSFBPktRefPictureSelIndic(super.ssrc, - rpsiPayloadType, rpsiBitString, rpsiPadding); - } - - } - - /** - * Decode Application specific feedback message - * - * @param aRawPkt - * @param start - */ - private void decAppLayerFB(byte[] aRawPkt, int start) { - // Application Message (FCI): variable length - int stringLength = (super.length - 2) * 4; - - alfBitString = new byte[stringLength]; - - System.arraycopy(aRawPkt, start, alfBitString, 0, stringLength); - - if (this.rtpSession.rtcpAVPFIntf != null) { - this.rtpSession.rtcpAVPFIntf.PSFBPktAppLayerFBReceived(super.ssrc, - alfBitString); - } - } - - /** - * Encode a Slice Loss Indication - */ - private void encSliceLossIndic() { - byte[] firstBytes; - byte[] numbBytes; - byte[] picBytes; - - int offset = 8; - // Loop over the FCI lines - for (int i = 0; i < sliFirst.length; i++) { - offset = 8 + 8 * i; - firstBytes = StaticProcs.uIntLongToByteWord(sliFirst[i] << 3); - numbBytes = StaticProcs.uIntLongToByteWord(sliNumber[i] << 2); - picBytes = StaticProcs.uIntIntToByteWord(sliPictureId[i]); - - super.rawPkt[offset] = firstBytes[2]; - super.rawPkt[offset + 1] = (byte) (firstBytes[3] | numbBytes[2]); - super.rawPkt[offset + 2] = numbBytes[3]; - super.rawPkt[offset + 3] = (byte) (numbBytes[3] | picBytes[1]); - } - } - - /** - * Encode a Reference Picture Selection Indication - * - */ - private void encRefPictureSelIndic() { - byte[] someBytes; - someBytes = StaticProcs.uIntIntToByteWord(rpsiPadding); - super.rawPkt[8] = someBytes[1]; - someBytes = StaticProcs.uIntIntToByteWord(rpsiPayloadType); - super.rawPkt[9] = someBytes[1]; - - System.arraycopy(rpsiBitString, 0, super.rawPkt, 10, - rpsiBitString.length); - } - - /** - * Encode Application Layer Feedback - * - */ - private void encAppLayerFB() { - // Application Message (FCI): variable length - System.arraycopy(alfBitString, 0, super.rawPkt, 8, alfBitString.length); - } - - /** - * Get the FMT (Feedback Message Type) - * - * @return value stored in .itemcount, same field - */ - protected int getFMT() { - return this.itemCount; - } - - /** - * Encode the packet into a byte[], saved in .rawPkt - * - * CompRtcpPkt will call this automatically - */ - protected void encode() { - switch (super.itemCount) { - case 1: // Picture Loss Indication - // Nothing to do really - super.rawPkt = new byte[24]; - break; - case 2: // Slice Loss Indication - super.rawPkt = new byte[24 + 4 * this.sliFirst.length]; - encSliceLossIndic(); - break; - case 3: // Reference Picture Selection Indication - super.rawPkt = new byte[24 + 2 + this.rpsiBitString.length / 4]; - encRefPictureSelIndic(); - break; - case 15: // Application Layer Feedback Messages - super.rawPkt = new byte[24 + this.alfBitString.length / 4]; - encAppLayerFB(); - break; - } - - byte[] someBytes = StaticProcs.uIntLongToByteWord(super.ssrc); - System.arraycopy(someBytes, 0, super.rawPkt, 4, 4); - someBytes = StaticProcs.uIntLongToByteWord(this.ssrcMediaSource); - System.arraycopy(someBytes, 0, super.rawPkt, 8, 4); - - writeHeaders(); - } - - /** - * Debug purposes only - */ - public void debugPrint() { - System.out.println("->RtcpPktPSFB.debugPrint() "); - - String str; - switch (super.itemCount) { - case 1: // Picture Loss Indication - System.out.println(" FMT: Picture Loss Indication"); - break; - case 2: // Slice Loss Indication - if (sliFirst != null) { - str = "sliFirst[].length: " + sliFirst.length; - } else { - str = "sliFirst[] is null"; - } - System.out.println(" FMT: Slice Loss Indication, " + str); - break; - case 3: // Reference Picture Selection Indication - if (rpsiBitString != null) { - str = "rpsiBitString[].length: " + rpsiBitString.length; - } else { - str = "rpsiBitString[] is null"; - } - System.out - .println(" FMT: Reference Picture Selection Indication, " - + str + " payloadType: " + this.rpsiPayloadType); - break; - case 15: // Application Layer Feedback Messages - if (alfBitString != null) { - str = "alfBitString[].length: " + alfBitString.length; - } else { - str = "alfBitString[] is null"; - } - System.out.println(" FMT: Application Layer Feedback Messages, " - + str); - break; - } - - System.out.println("<-RtcpPktPSFB.debugPrint() "); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktRR.java --- a/src/jlibrtp/RtcpPktRR.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,235 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * RTCP packets for Receiver Reports - * - * @author Arne Kepp - */ -public class RtcpPktRR extends RtcpPkt { - /** Array of participants to send Receiver Reports to */ - protected Participant[] reportees = null; - /** SSRC of participants the reports are for */ - protected long[] reporteeSsrc = null;// -1; //32 bits - /** Fraction (over 256) of packets lost */ - protected int[] lossFraction = null;// -1; //8 bits - /** Number of lost packets */ - protected int[] lostPktCount = null;// -1; //24 bits - /** Extended highest sequence received */ - protected long[] extHighSeqRecv = null;// -1; //32 bits - /** Interarrival jitter */ - protected long[] interArvJitter = null;// -1; //32 bits - /** Middle 32 bits of NTP when last SR was received */ - protected long[] timeStampLSR = null;// -1; //32 bits - /** Delay on last SRC */ - protected long[] delaySR = null;// -1; //32 bits - - /** - * Constructor for a packet with receiver reports - * - * @param reportees - * the participants on which to generate reports - * @param ssrc - * the SSRC of the sender, from the RTPSession - */ - protected RtcpPktRR(Participant[] reportees, long ssrc) { - super.packetType = 201; - // Fetch all the right stuff from the database - super.ssrc = ssrc; - this.reportees = reportees; - } - - /** - * - * - * If rcount < 0 we assume we have to parse the entire packet, otherwise - * we'll just parse the receiver report blocks (ie. the data came from a - * Sender Report packet) - * - * @param aRawPkt - * the byte[] with the report(s) - * @param start - * where in the raw packet to start reading - * @param rrCount - * the number of receiver reports, -1 if this does not come from - * an SR - */ - protected RtcpPktRR(byte[] aRawPkt, int start, int rrCount) { - // System.out.println("RtcpPktRR: " + rrCount + " start: " + start); - super.rawPkt = aRawPkt; - - if (rrCount < 0 - && (!super.parseHeaders(start) || packetType != 201 || super.length < 1)) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktRR.parseHeaders() etc. problem: " - + (!super.parseHeaders(start)) + " " - + packetType + " " + super.length); - } - super.problem = -201; - } - - int base; - if (rrCount > 0) { - base = start + 28; - } else { - base = start + 8; - rrCount = super.itemCount; - super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, start + 4); - } - - if (rrCount > 0) { - reporteeSsrc = new long[rrCount]; - lossFraction = new int[rrCount]; - lostPktCount = new int[rrCount]; - extHighSeqRecv = new long[rrCount]; - interArvJitter = new long[rrCount]; - timeStampLSR = new long[rrCount]; - delaySR = new long[rrCount]; - - for (int i = 0; i < rrCount; i++) { - int pos = base + i * 24; - reporteeSsrc[i] = StaticProcs.bytesToUIntLong(aRawPkt, pos); - lossFraction[i] = (int) aRawPkt[pos + 4]; - aRawPkt[pos + 4] = (byte) 0; - lostPktCount[i] = (int) StaticProcs.bytesToUIntLong(aRawPkt, - pos + 4); - extHighSeqRecv[i] = StaticProcs.bytesToUIntLong(aRawPkt, - pos + 8); - interArvJitter[i] = StaticProcs.bytesToUIntLong(aRawPkt, - pos + 12); - timeStampLSR[i] = StaticProcs - .bytesToUIntLong(aRawPkt, pos + 16); - delaySR[i] = StaticProcs.bytesToUIntLong(aRawPkt, pos + 20); - } - } - } - - /** - * Encode the packet into a byte[], saved in .rawPkt - * - * CompRtcpPkt will call this automatically - */ - protected void encode() { - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" -> RtcpPktRR.encode()"); - } - - byte[] rRs = null; - // Gather up the actual receiver reports - if (this.reportees != null) { - rRs = this.encodeRR(); - super.rawPkt = new byte[rRs.length + 8]; - System.arraycopy(rRs, 0, super.rawPkt, 8, rRs.length); - super.itemCount = reportees.length; - } else { - super.rawPkt = new byte[8]; - super.itemCount = 0; - } - - // Write the common header - super.writeHeaders(); - - // Add our SSRC (as sender) - StaticProcs.uIntLongToByteWord(super.ssrc, super.rawPkt, 4); - - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" <- RtcpPktRR.encode()"); - } - - } - - /** - * Encodes the individual Receiver Report blocks, - * - * so they can be used either in RR packets or appended to SR - * - * @return the encoded packets - */ - protected byte[] encodeRR() { - if (RTPSession.rtpDebugLevel > 10) { - System.out.println(" -> RtcpPktRR.encodeRR()"); - } - // assuming we will always create complete reports: - byte[] ret = new byte[24 * reportees.length]; - - // Write SR stuff - for (int i = 0; i < reportees.length; i++) { - int offset = 24 * i; - StaticProcs.uIntLongToByteWord(reportees[i].ssrc, ret, offset); - - // Cumulative number of packets lost - StaticProcs.uIntLongToByteWord(reportees[i] - .getLostPktCount(), ret, 4 + offset); - - // Write Cumulative number of packets lost and loss fraction to - // packet: - System.arraycopy(reportees[i].getFractionLost(), 0, ret, 4 + offset, 1); - - // Extended highest sequence received - StaticProcs.uIntLongToByteWord(reportees[i] - .getExtHighSeqRecv(), ret, 8 + offset); - - // Interarrival jitter - if (reportees[i].interArrivalJitter >= 0) { - StaticProcs - .uIntLongToByteWord((long) reportees[i].interArrivalJitter, ret, 12 + offset); - } else { - StaticProcs.uIntLongToByteWord(0, ret, 12 + offset); - } - - // Timestamp last sender report received - StaticProcs - .uIntLongToByteWord(reportees[i].timeStampLSR, ret, 16 + offset); - - // Delay since last sender report received, in terms of 1/655536 s = - // 0.02 ms - if (reportees[i].timeReceivedLSR > 0) { - StaticProcs.uIntLongToByteWord(reportees[i] - .delaySinceLastSR(), ret, 20 + offset); - } else { - StaticProcs.uIntLongToByteWord(0,ret, 20 + offset); - } - } - if (RTPSession.rtpDebugLevel > 10) { - System.out.println(" <- RtcpPktRR.encodeRR()"); - } - return ret; - } - - /** - * Debug purposes only - */ - public void debugPrint() { - System.out.println("RtcpPktRR.debugPrint() "); - if (reportees != null) { - for (int i = 0; i < reportees.length; i++) { - Participant part = reportees[i]; - System.out.println(" part.ssrc: " + part.ssrc - + " part.cname: " + part.cname); - } - } else { - for (int i = 0; i < reporteeSsrc.length; i++) { - System.out.println(" reporteeSSRC: " + reporteeSsrc[i] - + " timeStampLSR: " + timeStampLSR[i]); - } - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktRTPFB.java --- a/src/jlibrtp/RtcpPktRTPFB.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * RTCP packets for RTP Feedback Messages - * - * In line with RFC 4585, this packet currently only supports NACKs - * - * @author Arne Kepp - */ -public class RtcpPktRTPFB extends RtcpPkt { - /** If this packet was for a different SSRC */ - protected boolean notRelevant = false; - /** SSRC we are sending feeback to */ - protected long ssrcMediaSource = -1; - /** RTP sequence numbers of lost packets */ - protected int PID[]; - /** bitmask of following lost packets, shared index with PID */ - protected int BLP[]; - - /** - * Constructor for RTP Feedback Message - * - * @param ssrcPacketSender - * SSRC of sender, taken from RTPSession - * @param ssrcMediaSource - * SSRC of recipient of this message - * @param FMT - * the Feedback Message Subtype - * @param PID - * RTP sequence numbers of lost packets - * @param BLP - * bitmask of following lost packets, shared index with PID - */ - protected RtcpPktRTPFB(long ssrcPacketSender, long ssrcMediaSource, - int FMT, int[] PID, int[] BLP) { - super.packetType = 205; // RTPFB - super.itemCount = FMT; - this.PID = PID; - this.BLP = BLP; - } - - /** - * Constructor that parses a raw packet to retrieve information - * - * @param aRawPkt - * the raw packet to be parsed - * @param start - * the start of the packet, in bytes - * @param rtpSession - * the session on which the callback interface resides - */ - protected RtcpPktRTPFB(byte[] aRawPkt, int start, RTPSession rtpSession) { - if (RTPSession.rtpDebugLevel > 8) { - System.out.println(" -> RtcpPktRTPFB(byte[], int start)"); - } - - rawPkt = aRawPkt; - - if (!super.parseHeaders(start) || packetType != 205 || super.length < 2) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktRTPFB.parseHeaders() etc. problem"); - } - super.problem = -205; - } else { - // FMT = super.itemCount; - - ssrcMediaSource = StaticProcs.bytesToUIntLong(aRawPkt, 8 + start); - - if (ssrcMediaSource == rtpSession.ssrc) { - super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4 + start); - int loopStop = super.length - 2; - PID = new int[loopStop]; - BLP = new int[loopStop]; - int curStart = 12; - - // Loop over Feedback Control Information (FCI) fields - for (int i = 0; i < loopStop; i++) { - PID[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart); - BLP[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart + 2); - curStart += 4; - } - - rtpSession.rtcpAVPFIntf.RTPFBPktReceived(super.ssrc, - super.itemCount, PID, BLP); - } - } - - if (RTPSession.rtpDebugLevel > 8) { - System.out.println(" <- RtcpPktRTPFB()"); - } - } - - /** - * Encode the packet into a byte[], saved in .rawPkt - * - * CompRtcpPkt will call this automatically - */ - protected void encode() { - super.rawPkt = new byte[12 + this.PID.length * 4]; - - byte[] someBytes = StaticProcs.uIntLongToByteWord(super.ssrc); - System.arraycopy(someBytes, 0, super.rawPkt, 4, 4); - someBytes = StaticProcs.uIntLongToByteWord(this.ssrcMediaSource); - System.arraycopy(someBytes, 0, super.rawPkt, 8, 4); - - // Loop over Feedback Control Information (FCI) fields - int curStart = 12; - for (int i = 0; i < this.PID.length; i++) { - someBytes = StaticProcs.uIntIntToByteWord(PID[i]); - super.rawPkt[curStart++] = someBytes[0]; - super.rawPkt[curStart++] = someBytes[1]; - someBytes = StaticProcs.uIntIntToByteWord(BLP[i]); - super.rawPkt[curStart++] = someBytes[0]; - super.rawPkt[curStart++] = someBytes[1]; - } - writeHeaders(); - } - - /** - * Get the FMT (Feedback Message Type) - * - * @return value stored in .itemcount, same field - */ - protected int getFMT() { - return this.itemCount; - } - - /** - * Debug purposes only - */ - protected void debugPrint() { - System.out.println("->RtcpPktRTPFB.debugPrint() "); - System.out.println(" ssrcPacketSender: " + super.ssrc - + " ssrcMediaSource: " + ssrcMediaSource); - - if (this.PID != null && this.PID.length < 1) { - System.out - .println(" No Feedback Control Information (FCI) fields"); - } - - for (int i = 0; i < this.PID.length; i++) { - System.out.println(" FCI -> PID: " + PID[i] + " BLP: " + BLP[i]); - } - System.out.println("<-RtcpPktRTPFB.debugPrint() "); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktSDES.java --- a/src/jlibrtp/RtcpPktSDES.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,308 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.InetSocketAddress; - -/** - * RTCP packets for Source Descriptions - * - * @author Arne Kepp - */ -public class RtcpPktSDES extends RtcpPkt { - /** Whether the RTP Session object should be inclduded */ - boolean reportSelf = true; - /** The parent RTP Session object, holds participant database */ - RTPSession rtpSession = null; - /** The participants to create SDES packets for */ - protected Participant[] participants = null; - - /** - * Constructor to create a new SDES packet - * - * TODO: Currently the added participants are not actually encoded because - * the library lacks some support for acting as mixer or relay in other - * areas. - * - * @param reportThisSession - * include information from RTPSession as a participant - * @param rtpSession - * the session itself - * @param additionalParticipants - * additional participants to include - */ - protected RtcpPktSDES(boolean reportThisSession, RTPSession rtpSession, - Participant[] additionalParticipants) { - super.packetType = 202; - // Fetch all the right stuff from the database - reportSelf = reportThisSession; - participants = additionalParticipants; - this.rtpSession = rtpSession; - } - - /** - * Constructor that parses a received packet - * - * @param aRawPkt - * the byte[] containing the packet - * @param start - * where in the byte[] this packet starts - * @param socket - * the address from which the packet was received - * @param partDb - * the participant database - */ - protected RtcpPktSDES(byte[] aRawPkt, int start, InetSocketAddress socket, - ParticipantDatabase partDb) { - if (RTPSession.rtcpDebugLevel > 8) { - System.out.println(" -> RtcpPktSDES(byte[], ParticipantDabase)"); - } - rawPkt = aRawPkt; - - if (!super.parseHeaders(start) || packetType != 202) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktSDES.parseHeaders() etc. problem"); - } - super.problem = -202; - } else { - // System.out.println(" DECODE SIZE: " + super.length + - // " itemcount " + itemCount ); - - int curPos = 4 + start; - int curLength; - int curType; - long ssrc; - boolean endReached = false; - boolean newPart; - this.participants = new Participant[itemCount]; - - // Loop over SSRC SDES chunks - for (int i = 0; i < itemCount; i++) { - ssrc = StaticProcs.bytesToUIntLong(aRawPkt, curPos); - Participant part = partDb.getParticipant(ssrc); - if (part == null) { - if (RTPSession.rtcpDebugLevel > 1) { - System.out - .println("RtcpPktSDES(byte[], ParticipantDabase) adding new participant, ssrc:" - + ssrc + " " + socket); - } - - part = new Participant(socket, socket, ssrc); - newPart = true; - } else { - newPart = false; - } - - curPos += 4; - - // System.out.println("PRE endReached " + endReached + - // " curPos: " + curPos + " length:" + this.length + - // (!endReached && (curPos/4) < this.length)); - - while (!endReached && (curPos / 4) <= this.length) { - // System.out.println("endReached " + endReached + - // " curPos: " + curPos + " length:" + this.length); - curType = (int) aRawPkt[curPos]; - - if (curType == 0) { - curPos += 4 - (curPos % 4); - endReached = true; - } else { - curLength = (int) aRawPkt[curPos + 1]; - // System.out.println("curPos:"+curPos+" curType:"+curType+" curLength:"+curLength+" read from:"+(curPos - // + 1)); - - if (curLength > 0) { - byte[] item = new byte[curLength]; - // System.out.println("curPos:"+curPos+" arawPkt.length:"+aRawPkt.length+" curLength:"+curLength); - System.arraycopy(aRawPkt, curPos + 2, item, 0, - curLength); - - switch (curType) { - case 1: - part.cname = new String(item); - break; - case 2: - part.name = new String(item); - break; - case 3: - part.email = new String(item); - break; - case 4: - part.phone = new String(item); - break; - case 5: - part.loc = new String(item); - break; - case 6: - part.tool = new String(item); - break; - case 7: - part.note = new String(item); - break; - case 8: - part.priv = new String(item); - break; - } - // System.out.println("TYPE " + curType + " value:" - // + new String(item) ); - - } else { - switch (curType) { - case 1: - part.cname = null; - break; - case 2: - part.name = null; - break; - case 3: - part.email = null; - break; - case 4: - part.phone = null; - break; - case 5: - part.loc = null; - break; - case 6: - part.tool = null; - break; - case 7: - part.note = null; - break; - case 8: - part.priv = null; - break; - } - - } - curPos = curPos + curLength + 2; - } - } - - // Save the participant - this.participants[i] = part; - if (newPart) - partDb.addParticipant(2, part); - - // System.out.println("HEPPPPPP " + participants[i].cname ); - } - } - if (RTPSession.rtcpDebugLevel > 8) { - System.out.println(" <- RtcpPktSDES()"); - } - } - - /** - * Encode the packet into a byte[], saved in .rawPkt - * - * CompRtcpPkt will call this automatically - */ - protected void encode() { - byte[] temp = new byte[1450]; - byte[] someBytes = StaticProcs.uIntLongToByteWord(this.rtpSession.ssrc); - System.arraycopy(someBytes, 0, temp, 4, 4); - int pos = 8; - - String tmpString = null; - for (int i = 1; i < 9; i++) { - switch (i) { - case 1: - tmpString = this.rtpSession.cname; - break; - case 2: - tmpString = this.rtpSession.name; - break; - case 3: - tmpString = this.rtpSession.email; - break; - case 4: - tmpString = this.rtpSession.phone; - break; - case 5: - tmpString = this.rtpSession.loc; - break; - case 6: - tmpString = this.rtpSession.tool; - break; - case 7: - tmpString = this.rtpSession.note; - break; - case 8: - tmpString = this.rtpSession.priv; - break; - } - - if (tmpString != null) { - someBytes = tmpString.getBytes(); - temp[pos] = (byte) i; - temp[pos + 1] = (byte) someBytes.length; - System.arraycopy(someBytes, 0, temp, pos + 2, someBytes.length); - // System.out.println("i: "+i+" pos:"+pos+" someBytes.length:"+someBytes.length); - pos = pos + someBytes.length + 2; - // if(i == 1 ) { - // System.out.println("trueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + - // tmpString); - // } - } - } - int leftover = pos % 4; - if (leftover == 1) { - temp[pos] = (byte) 0; - temp[pos + 1] = (byte) 1; - pos += 3; - } else if (leftover == 2) { - temp[pos] = (byte) 0; - temp[pos + 1] = (byte) 0; - pos += 2; - } else if (leftover == 3) { - temp[pos] = (byte) 0; - temp[pos + 1] = (byte) 3; - pos += 5; - } - - // TODO Here we ought to loop over participants, if we're doing SDES for - // other participants. - - super.rawPkt = new byte[pos]; - itemCount = 1; - // This looks wrong, but appears to be fine.. - System.arraycopy(temp, 0, super.rawPkt, 0, pos); - writeHeaders(); - } - - /** - * Debug purposes only - */ - public void debugPrint() { - System.out.println("RtcpPktSDES.debugPrint() "); - if (participants != null) { - for (int i = 0; i < participants.length; i++) { - Participant part = participants[i]; - System.out.println(" part.ssrc: " + part.ssrc - + " part.cname: " + part.cname + " part.loc: " - + part.loc); - } - } else { - System.out - .println(" nothing to report (only valid for received packets)"); - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtcpPktSR.java --- a/src/jlibrtp/RtcpPktSR.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * RTCP packets for Sender Reports - * - * @author Arne Kepp - */ -public class RtcpPktSR extends RtcpPkt { - /** NTP timestamp, MSB */ - protected long ntpTs1 = -1; // 32 bits - /** NTP timestamp, LSB */ - protected long ntpTs2 = -1; // 32 bits - /** RTP timestamp */ - protected long rtpTs = -1; // 32 bits - /** Senders packet count */ - protected long sendersPktCount = -1; // 32 bits - /** Senders octet count */ - protected long sendersOctCount = -1; // 32 bits - /** RR packet with receiver reports that we can append */ - protected RtcpPktRR rReports = null; - - /** - * Constructor for a new Sender Report packet - * - * @param ssrc - * the senders SSRC, presumably from RTPSession - * @param pktCount - * packets sent in this session - * @param octCount - * octets sent in this session - * @param rReports - * receiver reports, as RR packets, to be included in this packet - */ - protected RtcpPktSR(long ssrc, long pktCount, long octCount, - RtcpPktRR rReports) { - // Fetch all the right stuff from the database - super.ssrc = ssrc; - super.packetType = 200; - sendersPktCount = pktCount; - sendersOctCount = octCount; - this.rReports = rReports; - } - - /** - * Constructor that parses a received packet - * - * @param aRawPkt - * the raw packet - * @param start - * the position at which SR starts - * @param length - * used to determine number of included receiver reports - */ - protected RtcpPktSR(byte[] aRawPkt, int start, int length) { - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" -> RtcpPktSR(rawPkt)"); - } - - super.rawPkt = aRawPkt; - - if (!super.parseHeaders(start) || packetType != 200) { - if (RTPSession.rtpDebugLevel > 2) { - System.out - .println(" <-> RtcpPktSR.parseHeaders() etc. problem: " - + (!super.parseHeaders(start)) + " " - + packetType + " " + super.length); - } - super.problem = -200; - } else { - super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4 + start); - if (length > 11) - ntpTs1 = StaticProcs.bytesToUIntLong(aRawPkt, 8 + start); - if (length > 15) - ntpTs2 = StaticProcs.bytesToUIntLong(aRawPkt, 12 + start); - if (length > 19) - rtpTs = StaticProcs.bytesToUIntLong(aRawPkt, 16 + start); - if (length > 23) - sendersPktCount = StaticProcs.bytesToUIntLong(aRawPkt, - 20 + start); - if (length > 27) - sendersOctCount = StaticProcs.bytesToUIntLong(aRawPkt, - 24 + start); - - // RRs attached? - if (itemCount > 0) { - rReports = new RtcpPktRR(rawPkt, start, itemCount); - } - } - - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" <- RtcpPktSR(rawPkt)"); - } - } - - /** - * Encode the packet into a byte[], saved in .rawPkt - * - * CompRtcpPkt will call this automatically - */ - protected void encode() { - if (RTPSession.rtpDebugLevel > 9) { - if (this.rReports != null) { - System.out - .println(" -> RtcpPktSR.encode() receptionReports.length: " - + this.rReports.length); - } else { - System.out - .println(" -> RtcpPktSR.encode() receptionReports: null"); - } - } - - if (this.rReports != null) { - super.itemCount = this.rReports.reportees.length; - - byte[] tmp = this.rReports.encodeRR(); - super.rawPkt = new byte[tmp.length + 28]; - // super.length = (super.rawPkt.length / 4) - 1; - - System.arraycopy(tmp, 0, super.rawPkt, 28, tmp.length); - - } else { - super.itemCount = 0; - super.rawPkt = new byte[28]; - // super.length = 6; - } - // Write the common header - super.writeHeaders(); - - // Convert to NTP and chop up - long timeNow = System.currentTimeMillis(); - ntpTs1 = 2208988800L + (timeNow / 1000); - long ms = timeNow % 1000; - double tmp = ((double) ms) / 1000.0; - tmp = tmp * (double) 4294967295L; - ntpTs2 = (long) tmp; - rtpTs = System.currentTimeMillis(); - - // Write SR stuff - StaticProcs.uIntLongToByteWord(super.ssrc, super.rawPkt, 4); - StaticProcs.uIntLongToByteWord(ntpTs1, super.rawPkt, 8); - StaticProcs.uIntLongToByteWord(ntpTs2, super.rawPkt, 12); - StaticProcs.uIntLongToByteWord(rtpTs, super.rawPkt, 16); - StaticProcs.uIntLongToByteWord(sendersPktCount, super.rawPkt, 20); - StaticProcs.uIntLongToByteWord(sendersOctCount, super.rawPkt, 24); - - if (RTPSession.rtpDebugLevel > 9) { - System.out.println(" <- RtcpPktSR.encode() ntpTs1: " - + Long.toString(ntpTs1) + " ntpTs2: " - + Long.toString(ntpTs2)); - } - } - - /** - * Debug purposes only - */ - public void debugPrint() { - System.out.println("RtcpPktSR.debugPrint() "); - System.out.println(" SSRC:" + Long.toString(super.ssrc) + " ntpTs1:" - + Long.toString(ntpTs1) + " ntpTS2:" + Long.toString(ntpTs2) - + " rtpTS:" + Long.toString(rtpTs) + " senderPktCount:" - + Long.toString(sendersPktCount) + " sendersOctetCount:" - + Long.toString(sendersOctCount)); - if (this.rReports != null) { - System.out.print(" Part of Sender Report: "); - this.rReports.debugPrint(); - System.out.println(" End Sender Report"); - } else { - System.out - .println("No Receiver Reports associated with this Sender Report."); - } - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/RtpPkt.java --- a/src/jlibrtp/RtpPkt.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -import java.net.DatagramPacket; - -/** - * RtpPkt is the basic class for creating and parsing RTP packets. - * - * There are two ways of instantiating an RtpPkt. One is for packets that you - * wish to send, which requires that you provide basic information about the - * packet and a payload. Upon calling encode() the fields of the structure are - * written into a bytebuffer, in the form that it would sent across the network, - * excluding the UDP headers. - * - * The other way is by passing a bytebuffer. The assumption is that this is a - * packet that has been received from the network, excluding UDP headers, and - * the bytebuffer will be parsed into the correct fields. - * - * The class keeps track of changes. Therefore, modifications are possible after - * calling encode(), if necessary, the raw version of the packet will be - * regenerated on subsequent requests. - * - * @author Arne Kepp - */ -public class RtpPkt { - /** Whether the packet has been changed since encode() */ - private boolean rawPktCurrent = false; - /** The version, always 2, 2 bits */ - private int version = 2; // 2 bits - /** Whether the packet is padded, 1 bit */ - private int padding; // 1 bit - /** Whether and extension is used, 1 bit */ - private int extension = 0; // 1 bit - /** Whether the packet is marked, 1 bit */ - private int marker = 0; // 1 bit - /** What payload type is used, 7 bits */ - private int payloadType; // - /** The sequence number, taken from RTP Session, 16 bits */ - private int seqNumber; // 16 bits - /** The RTP timestamp, 32bits */ - private long timeStamp; // 32 bits - /** The SSRC of the packet sender, 32 bits */ - private long ssrc; // 32 bits - /** SSRCs of contributing sources, 32xn bits, n<16 */ - private long[] csrcArray = new long[0];// - - /** Contains the actual data (eventually) */ - private byte[] rawPkt = null; - - - - /** The actual data, without any RTP stuff */ - //private byte[] payload = null; - private DatagramPacket datagramPacket; - - /** - * Construct a packet-instance. The ByteBuffer required for UDP transmission - * can afterwards be obtained from getRawPkt(). If you need to set - * additional parameters, such as the marker bit or contributing sources, - * you should do so before calling getRawPkt; - * - * @param aTimeStamp - * RTP timestamp for data - * @param syncSource - * the SSRC, usually taken from RTPSession - * @param seqNum - * Sequency number - * @param plt - * Type of payload - * @param pl - * Payload, the actual data - */ - protected void initPacket(long aTimeStamp, long syncSource, int seqNum, int plt, - byte[] pl) { - int test = 0; - test += setTimeStamp(aTimeStamp); - test += setSsrc(syncSource); - test += setSeqNumber(seqNum); - test += setPayloadType(plt); - //test += setPayload(pl); //TODO: faire d'une manière propre - datagramPacket = null; - if (test != 0) { - System.out.println("RtpPkt() failed, check with checkPkt()"); - } - rawPktCurrent = true; - if (RTPSession.rtpDebugLevel > 5) { - System.out - .println("<--> RtpPkt(aTimeStamp, syncSource, seqNum, plt, pl)"); - } - } - - /** - * Construct a packet-instance from an raw packet (believed to be RTP). The - * UDP-headers must be removed before invoking this method. Call checkPkt on - * the instance to verify that it was successfully parsed. - * - * @param aRawPkt - * The data-part of a UDP-packet believed to be RTP - * @param packetSize - * the number of valid octets in the packet, should be - * aRawPkt.length - */ - public RtpPkt(byte[] aRawPkt, int packetSize, DatagramPacket packet) { - initPacket(aRawPkt, packetSize, packet); - } - - public RtpPkt() { - } - - public RtpPkt(long aTimeStamp, long syncSource, int seqNum, int plt, - byte[] pl) { - initPacket(aTimeStamp, syncSource, seqNum, plt, pl); - } - - protected void initPacket(byte[] aRawPkt, int packetSize, DatagramPacket packet) { - if (RTPSession.rtpDebugLevel > 5) { - System.out.println("-> RtpPkt(aRawPkt)"); - } - // Check size, need to have at least a complete header - if (aRawPkt == null) { - System.out.println("RtpPkt(byte[]) Packet null"); - } - - int remOct = packetSize - 12; - if (remOct >= 0) { - rawPkt = aRawPkt; // Store it - // Interrogate the packet - datagramPacket = packet; - sliceFirstLine(); - if (version == 2) { - sliceTimeStamp(); - sliceSSRC(); - if (remOct > 4 && getCsrcCount() > 0) { - sliceCSRCs(); - remOct -= csrcArray.length * 4; // 4 octets per CSRC - } - // TODO Extension - /*if (remOct > 0) { - slicePayload(remOct); - }*/ - - // Sanity checks - checkPkt(); - - // Mark the buffer as current - rawPktCurrent = true; - } else { - System.out - .println("RtpPkt(byte[]) Packet is not version 2, giving up."); - } - } else { - System.out.println("RtpPkt(byte[]) Packet too small to be sliced"); - } - rawPktCurrent = true; - if (RTPSession.rtpDebugLevel > 5) { - System.out.println("<- RtpPkt(aRawPkt)"); - } - } - - /********************************************************************************************************* - * Reading stuff - *********************************************************************************************************/ - protected int checkPkt() { - // TODO, check for version 2 etc - return 0; - } - - protected int getHeaderLength() { - // TODO include extension - return 12 + 4 * getCsrcCount(); - } - - protected int getPayloadLength() { - return rawPkt.length - getHeaderLength(); - } - - // public int getPaddingLength() { - // return lenPadding; - // } - protected int getVersion() { - return version; - } - - // public boolean isPadded() { - // if(lenPadding > 0) { - // return true; - // }else { - // return false; - // } - // } - // public int getHeaderExtension() { - // TODO - // } - protected boolean isMarked() { - return (marker != 0); - } - - protected int getPayloadType() { - return payloadType; - } - - public int getSeqNumber() { - return seqNumber; - } - - protected long getTimeStamp() { - return timeStamp; - } - - protected long getSsrc() { - return ssrc; - } - - protected int getCsrcCount() { - if (csrcArray != null) { - return csrcArray.length; - } else { - return 0; - } - } - - protected long[] getCsrcArray() { - return csrcArray; - } - - /** - * Encodes the a - */ - protected byte[] encode() { - if (!rawPktCurrent || rawPkt == null) { - writePkt(); - android.util.Log.d("RtpPkt", "writePkt"); - } - return rawPkt; - } - - /* For debugging purposes */ - protected void printPkt() { - System.out - .print("V:" + version + " P:" + padding + " EXT:" + extension); - System.out.println(" CC:" + getCsrcCount() + " M:" + marker + " PT:" - + payloadType + " SN: " + seqNumber); - System.out.println("Timestamp:" + timeStamp - + "(long output as int, may be 2s complement)"); - System.out.println("SSRC:" + ssrc - + "(long output as int, may be 2s complement)"); - for (int i = 0; i < getCsrcCount(); i++) { - System.out.println("CSRC:" + csrcArray[i] - + "(long output as int, may be 2s complement)"); - } - - } - - /********************************************************************************************************* - * Setting stuff - *********************************************************************************************************/ - protected void setMarked(boolean mark) { - rawPktCurrent = false; - if (mark) { - marker = 1; - } else { - marker = 0; - } - } - - // public int setHeaderExtension() { - // TODO - // } - public int setPayloadType(int plType) { - int temp = (plType & 0x0000007F); // 7 bits, checks in RTPSession as - // well. - if (temp == plType) { - rawPktCurrent = false; - payloadType = temp; - return 0; - } else { - return -1; - } - } - - protected int setSeqNumber(int number) { - if (number <= 65536 && number >= 0) { - rawPktCurrent = false; - seqNumber = number; - return 0; - } else { - System.out.println("RtpPkt.setSeqNumber: invalid number"); - return -1; - } - } - - protected int setTimeStamp(long time) { - rawPktCurrent = false; - timeStamp = time; - return 0; // Naive for now - } - - protected int setSsrc(long source) { - rawPktCurrent = false; - ssrc = source; - return 0; // Naive for now - } - - protected int setCsrcs(long[] contributors) { - if (contributors.length <= 16) { - csrcArray = contributors; - return 0; - } else { - System.out - .println("RtpPkt.setCsrcs: Cannot have more than 16 CSRCs"); - return -1; - } - } - - /*protected int setPayload(byte[] data) { - // TODO Padding - if (data.length < (1500 - 12)) { - rawPktCurrent = false; - payload = data; - return 0; - } else { - System.out - .println("RtpPkt.setPayload: Cannot carry more than 1480 bytes for now."); - return -1; - } - }*/ - - public byte[] getPayload() { - return rawPkt; - } - - /********************************************************************************************************* - * Private functions - *********************************************************************************************************/ - // Generate a bytebyffer representing the packet, store it. - private void writePkt() { - int bytes = getPayloadLength(); - int headerLen = getHeaderLength(); - int csrcLen = getCsrcCount(); - rawPkt = new byte[headerLen + bytes]; - - // The first line contains, version and various bits - writeFirstLine(); - byte[] someBytes = StaticProcs.uIntLongToByteWord(timeStamp); - for (int i = 0; i < 4; i++) { - rawPkt[i + 4] = someBytes[i]; - } - // System.out.println("writePkt timeStamp:" + rawPkt[7]); - - someBytes = StaticProcs.uIntLongToByteWord(ssrc); - System.arraycopy(someBytes, 0, rawPkt, 8, 4); - // System.out.println("writePkt ssrc:" + rawPkt[11]); - - for (int i = 0; i < csrcLen; i++) { - someBytes = StaticProcs.uIntLongToByteWord(csrcArray[i]); - System.arraycopy(someBytes, 0, rawPkt, 12 + 4 * i, 4); - } - // TODO Extension - - // Payload - //System.arraycopy(payload, 0, rawPkt, headerLen, bytes); - rawPktCurrent = true; - } - - void writeHeader() { - //int bytes = rawPkt.length - 12; - //int headerLen = getHeaderLength(); - int csrcLen = getCsrcCount(); - - // The first line contains, version and various bits - writeFirstLine(); - StaticProcs.uIntLongToByteWord(timeStamp, rawPkt, 4); - // System.out.println("writePkt timeStamp:" + rawPkt[7]); - - StaticProcs.uIntLongToByteWord(ssrc, rawPkt, 8); - //System.arraycopy(someBytes, 0, rawPkt, 8, 4); - // System.out.println("writePkt ssrc:" + rawPkt[11]); - - for (int i = 0; i < csrcLen; i++) { - StaticProcs.uIntLongToByteWord(csrcArray[i], rawPkt, 12 + 4 * i); - //System.arraycopy(someBytes, 0, rawPkt, 12 + 4 * i, 4); - } - // TODO Extension - - // Payload - //System.arraycopy(payload, 0, rawPkt, headerLen, bytes); - rawPktCurrent = true; - } - - // Writes the first 4 octets of the RTP packet - protected void writeFirstLine() { - byte aByte = 0; - aByte |= (version << 6); - aByte |= (padding << 5); - aByte |= (extension << 4); - aByte |= (getCsrcCount()); - rawPkt[0] = aByte; - aByte = 0; - aByte |= (marker << 7); - aByte |= payloadType; - rawPkt[1] = aByte; - StaticProcs.uIntIntToByteWord(seqNumber, rawPkt, 2); - } - - // Picks apart the first 4 octets of an RTP packet - private void sliceFirstLine() { - version = ((rawPkt[0] & 0xC0) >>> 6); - padding = ((rawPkt[0] & 0x20) >>> 5); - extension = ((rawPkt[0] & 0x10) >>> 4); - //csrcArray = new long[(rawPkt[0] & 0x0F)]; - marker = ((rawPkt[1] & 0x80) >> 7); - payloadType = (rawPkt[1] & 0x7F); - seqNumber = StaticProcs.bytesToUIntInt(rawPkt, 2); - } - - // Takes the 4 octets representing the timestamp - private void sliceTimeStamp() { - timeStamp = StaticProcs.bytesToUIntLong(rawPkt, 4); - } - - // Takes the 4 octets representing the SSRC - private void sliceSSRC() { - ssrc = StaticProcs.bytesToUIntLong(rawPkt, 8); - } - - // Check the length of the csrcArray (set during sliceFirstLine) - private void sliceCSRCs() { - for (int i = 0; i < csrcArray.length; i++) { - ssrc = StaticProcs.bytesToUIntLong(rawPkt, i * 4 + 12); - } - } - - // Extensions //TODO - /*private void slicePayload(int bytes) { - payload = new byte[bytes]; - int headerLen = getHeaderLength(); - - System.arraycopy(rawPkt, headerLen, payload, 0, bytes); - }*/ - - public void setRawPkt(byte[] rawPkt) { - this.rawPkt = rawPkt; - } - - public DatagramPacket getDatagramPacket() { - return datagramPacket; - } -} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/StaticProcs.java --- a/src/jlibrtp/StaticProcs.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,298 +0,0 @@ -/** - * Java RTP Library (jlibrtp) - * Copyright (C) 2006 Arne Kepp - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package jlibrtp; - -/** - * Generic functions for converting between unsigned integers and byte[]s. - * - * @author Arne Kepp - */ -public class StaticProcs { - - /** - * Converts an integer into an array of bytes. Primarily used for 16 bit - * unsigned integers, ignore the first two octets. - * - * @param i - * a 16 bit unsigned integer in an int - * @return byte[2] representing the integer as unsigned, most significant - * bit first. - */ - public static byte[] uIntIntToByteWord(int i) { - byte[] byteWord = new byte[2]; - byteWord[0] = (byte) ((i >> 8) & 0x000000FF); - byteWord[1] = (byte) (i & 0x00FF); - return byteWord; - } - - public static void uIntIntToByteWord(int i, byte[] byteWord, int srcPos) { - byteWord[0 + srcPos] = (byte) ((i >> 8) & 0x000000FF); - byteWord[1 + srcPos] = (byte) (i & 0x00FF); - } - - /** - * Converts an unsigned 32 bit integer, stored in a long, into an array of - * bytes. - * - * @param j - * a long - * @return byte[4] representing the unsigned integer, most significant bit - * first. - */ - public static byte[] uIntLongToByteWord(long j) { - int i = (int) j; - byte[] byteWord = new byte[4]; - byteWord[0] = (byte) ((i >>> 24) & 0x000000FF); - byteWord[1] = (byte) ((i >> 16) & 0x000000FF); - byteWord[2] = (byte) ((i >> 8) & 0x000000FF); - byteWord[3] = (byte) (i & 0x00FF); - return byteWord; - } - - public static void uIntLongToByteWord(long j, byte[] byteword, int srcPos) { - int i = (int) j; - byteword[0 + srcPos] = (byte) ((i >>> 24) & 0x000000FF); - byteword[1 + srcPos] = (byte) ((i >> 16) & 0x000000FF); - byteword[2 + srcPos] = (byte) ((i >> 8) & 0x000000FF); - byteword[3 + srcPos] = (byte) (i & 0x00FF); - } - - /** - * Combines two bytes (most significant bit first) into a 16 bit unsigned - * integer. - * - * @param index - * of most significant byte - * @return int with the 16 bit unsigned integer - */ - public static int bytesToUIntInt(byte[] bytes, int index) { - int accum = 0; - int i = 1; - for (int shiftBy = 0; shiftBy < 16; shiftBy += 8) { - accum |= ((long) (bytes[index + i] & 0xff)) << shiftBy; - i--; - } - return accum; - } - - /** - * Combines four bytes (most significant bit first) into a 32 bit unsigned - * integer. - * - * @param bytes - * @param index - * of most significant byte - * @return long with the 32 bit unsigned integer - */ - public static long bytesToUIntLong(byte[] bytes, int index) { - long accum = 0; - int i = 3; - for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) { - accum |= ((long) (bytes[index + i] & 0xff)) << shiftBy; - i--; - } - return accum; - } - - /** - * Converts an arbitrary number of bytes, assumed to represent an unsigned - * integer, to a Java long - */ - /* - * public static long bytesToUintLong(byte[] bytes, int firstByte, int - * lastByte) { long accum = 0; int i = lastByte - firstByte; if(i > 7) { - * System.out.println( - * "!!!! StaticProcs.bytesToUintLong() Can't convert more than 63 bits!"); - * return -1; } int stop = (i+1)*8; - * - * for (int shiftBy = 0; shiftBy < stop; shiftBy += 8 ) { accum |= ( (long)( - * bytes[firstByte + i] & 0xff ) ) << shiftBy; i--; } return accum; } - */ - - /** - * Converts an arbitrary number of bytes, assumed to represent an unsigned - * integer, to a Java int - */ - /* - * public static int bytesToUintInt(byte[] bytes, int firstByte, int - * lastByte) { int accum = 0; int i = lastByte - firstByte; if(i > 3) { - * System.out.println( - * "!!!! StaticProcs.bytesToUintLong() Can't convert more than 31 bits!"); - * return -1; } int stop = (i+1)*8; - * - * for (int shiftBy = 0; shiftBy < stop; shiftBy += 8 ) { accum |= ( (long)( - * bytes[firstByte + i] & 0xff ) ) << shiftBy; i--; } return accum; } - */ - - /** - * Recreates a UNIX timestamp based on the NTP representation used in RTCP - * SR packets - * - * @param ntpTs1 - * from RTCP SR packet - * @param ntpTs2 - * from RTCP SR packet - * @return the UNIX timestamp - */ - public static long undoNtpMess(long ntpTs1, long ntpTs2) { - long timeVal = (ntpTs1 - 2208988800L) * 1000; - - double tmp = (1000.0 * (double) ntpTs2) / ((double) 4294967295L); - long ms = (long) tmp; - // System.out.println(" timeVal: " +Long.toString(timeVal)+ " ms " + - // Long.toString(ms)); - timeVal += ms; - - return timeVal; - } - - /** - * Get the bits of a byte - * - * @param aByte - * the byte you wish to convert - * @return a String of 1's and 0's - */ - public static String bitsOfByte(byte aByte) { - int temp; - String out = ""; - for (int i = 7; i >= 0; i--) { - temp = (aByte >>> i); - temp &= 0x0001; - out += ("" + temp); - } - return out; - } - - /** - * Get the hex representation of a byte - * - * @param aByte - * the byte you wish to convert - * @return a String of two chars 0-1,A-F - */ - public static String hexOfByte(byte aByte) { - String out = ""; - - for (int i = 0; i < 2; i++) { - int temp = (int) aByte; - if (temp < 0) { - temp += 256; - } - if (i == 0) { - temp = temp / 16; - } else { - temp = temp % 16; - } - - if (temp > 9) { - switch (temp) { - case 10: - out += "A"; - break; - case 11: - out += "B"; - break; - case 12: - out += "C"; - break; - case 13: - out += "D"; - break; - case 14: - out += "E"; - break; - case 15: - out += "F"; - break; - } - } else { - out += Integer.toString(temp); - } - } - return out; - } - - /** - * Get the hex representation of a byte - * - * @param hex - * 4 bytes the byte you wish to convert - * @return a String of two chars 0-1,A-F - */ - public static byte byteOfHex(byte[] hex) { - byte retByte = 0; - Byte tmp; - int val = 0; - - // First 4 bits - tmp = hex[0]; - val = tmp.intValue(); - if (val > 64) { - // Letter - val -= 55; - } else { - // Number - val -= 48; - } - retByte = ((byte) (val << 4)); - - // Last 4 bits - tmp = hex[1]; - val = tmp.intValue(); - if (val > 64) { - // Letter - val -= 55; - } else { - // Number - val -= 48; - } - retByte |= ((byte) val); - - return retByte; - } - - /** - * Print the bits of a byte to standard out. For debugging. - * - * @param aByte - * the byte you wish to print out. - */ - public static void printBits(byte aByte) { - int temp; - for (int i = 7; i >= 0; i--) { - temp = (aByte >>> i); - temp &= 0x0001; - System.out.print("" + temp); - } - System.out.println(); - } - - public static String bitsOfBytes(byte[] bytes) { - String str = ""; - // Expensive, but who cares - for (int i = 0; i < bytes.length; i++) { - str += bitsOfByte(bytes[i]) + " "; - if ((i + 1) % 4 == 0) - str += "\n"; - } - - return str; - } -} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/jlibrtp/package.html --- a/src/jlibrtp/package.html Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ - - -

The jlibrtp package contains the core classes of jlibrtp. Most of these classes - are protected or private, developers looking to use jlibrtp should only concern - themselves with

-
    -
  • RTPSession - the main session object -
  • Participant - participant objects -
  • DataFrame - the containers in which data is returned -
  • RTPAppIntf - the mininum callback interface -
  • RTPCAppIntf - optional interface for receing RTCP packets -
  • RTCPAVPFIntf - optional interface for RTP with feedback -
  • DebugAppIntf - optional interface for debugging -
-

- DebugAppIntf is great for checking network problems and keeping track of packets. - If you need extensive debugging you should statically change the debug values in RTPSession.java - and pay attention to the standard output. -

- - - \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/G711.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/media/G711.java Sat Jan 23 22:19:43 2010 +0100 @@ -0,0 +1,397 @@ +package src.org.sipdroid.media; + +/** + * G.711 codec. This class provides methods for u-law, A-law and linear PCM + * conversions. + */ +public class G711 { + /* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + + static final short[] a2s = new short[256]; + static final int[] _a2s = { + + 60032, 60288, 59520, 59776, 61056, 61312, 60544, 60800, + 57984, 58240, 57472, 57728, 59008, 59264, 58496, 58752, + 62784, 62912, 62528, 62656, 63296, 63424, 63040, 63168, + 61760, 61888, 61504, 61632, 62272, 62400, 62016, 62144, + 43520, 44544, 41472, 42496, 47616, 48640, 45568, 46592, + 35328, 36352, 33280, 34304, 39424, 40448, 37376, 38400, + 54528, 55040, 53504, 54016, 56576, 57088, 55552, 56064, + 50432, 50944, 49408, 49920, 52480, 52992, 51456, 51968, + 65192, 65208, 65160, 65176, 65256, 65272, 65224, 65240, + 65064, 65080, 65032, 65048, 65128, 65144, 65096, 65112, + 65448, 65464, 65416, 65432, 65512, 65528, 65480, 65496, + 65320, 65336, 65288, 65304, 65384, 65400, 65352, 65368, + 64160, 64224, 64032, 64096, 64416, 64480, 64288, 64352, + 63648, 63712, 63520, 63584, 63904, 63968, 63776, 63840, + 64848, 64880, 64784, 64816, 64976, 65008, 64912, 64944, + 64592, 64624, 64528, 64560, 64720, 64752, 64656, 64688, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 + + }; + + static final byte[] s2a = new byte[65536]; + static final int[] _s2a = { + + 213,212,215,214,209,208,211,210,221,220,223,222,217,216,219,218, + 197,196,199,198,193,192,195,194,205,204,207,206,201,200,203,202, + 245,245,244,244,247,247,246,246,241,241,240,240,243,243,242,242, + 253,253,252,252,255,255,254,254,249,249,248,248,251,251,250,250, + 229,229,229,229,228,228,228,228,231,231,231,231,230,230,230,230, + 225,225,225,225,224,224,224,224,227,227,227,227,226,226,226,226, + 237,237,237,237,236,236,236,236,239,239,239,239,238,238,238,238, + 233,233,233,233,232,232,232,232,235,235,235,235,234,234,234,234, + 149,149,149,149,149,149,149,149,148,148,148,148,148,148,148,148, + 151,151,151,151,151,151,151,151,150,150,150,150,150,150,150,150, + 145,145,145,145,145,145,145,145,144,144,144,144,144,144,144,144, + 147,147,147,147,147,147,147,147,146,146,146,146,146,146,146,146, + 157,157,157,157,157,157,157,157,156,156,156,156,156,156,156,156, + 159,159,159,159,159,159,159,159,158,158,158,158,158,158,158,158, + 153,153,153,153,153,153,153,153,152,152,152,152,152,152,152,152, + 155,155,155,155,155,155,155,155,154,154,154,154,154,154,154,154, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, + 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, + 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, + 130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, + 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, + 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, + 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, + 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, + 137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, + 136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, + 138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, + 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, + 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, + 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, + 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, + 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, + 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, + 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, + 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, + 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, + 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, + 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, + 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, + 179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, + 179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, + 178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, + 178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, + 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, + 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, + 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, + 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, + 191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, + 191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, + 190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, + 190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, + 185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, + 185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, + 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, + 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, + 187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, + 187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, + 186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, + 186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, + 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, + 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, + 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, + 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, + 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, + 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, + 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, + 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, + 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, + 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, + 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, + 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, + 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, + 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, + 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, + 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, + 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, + 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, + 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, + 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, + 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, + 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, + 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, + 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, + 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, + 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, + 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, + 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, + 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, + 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, + 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, + 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, + 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, + 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, + 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, + 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, + 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, + 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, + 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, + 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, + 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, + 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, + 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, + 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, + 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, + 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, + 106,106,106,106,107,107,107,107,104,104,104,104,105,105,105,105, + 110,110,110,110,111,111,111,111,108,108,108,108,109,109,109,109, + 98, 98, 98, 98, 99, 99, 99, 99, 96, 96, 96, 96, 97, 97, 97, 97, + 102,102,102,102,103,103,103,103,100,100,100,100,101,101,101,101, + 122,122,123,123,120,120,121,121,126,126,127,127,124,124,125,125, + 114,114,115,115,112,112,113,113,118,118,119,119,116,116,117,117, + 74, 75, 72, 73, 78, 79, 76, 77, 66, 67, 64, 65, 70, 71, 68, 69, + 90, 91, 88, 89, 94, 95, 92, 93, 82, 83, 80, 81, 86, 87, 84, 85 + }; + + //change G711 ulaw start + static final int _u2a[] = { /* u- to A-law conversions */ + 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 7, 7, 8, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 27, 29, 31, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, + 46, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128}; + + static final int _a2u[] = { /* A- to u-law conversions */ + 1, 3, 5, 7, 9, 11, 13, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 48, 49, 49, + 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}; + + //change end + + public static void init() { + } + + static { + int i; + for (i = 0; i < 256; i++) + a2s[i] = (short)_a2s[i]; + for (i = 0; i < 65536; i++) + s2a[i] = (byte)_s2a[i >> 4]; + } + + public static void alaw2linear(byte alaw[],short lin[],int frames) { + int i; + for (i = 0; i < frames; i++) + lin[i] = a2s[alaw[i+12] & 0xff]; + } + + public static void linear2alaw(short lin[],int offset,byte alaw[],int frames) { + int i; + for (i = 0; i < frames; i++) + alaw[i+12] = s2a[lin[i+offset] & 0xffff]; + } + + //change g711 ulaw start + protected static int alaw2ulaw(int aval) + { aval&=0xff; + return ((aval & 0x80)!=0)? (0xFF^_a2u[aval^0xD5]) : (0x7F^_a2u[aval^0x55]); + } + + protected static int ulaw2alaw(int uval) + { uval&=0xff; + return ((uval&0x80)!=0)? (0xD5^(_u2a[0xFF^uval]-1)) : (0x55^(_u2a[0x7F^uval]-1)); + } + + public static void ulaw2linear(byte ulaw[],short lin[],int frames) { + int i; + for (i = 0; i < frames; i++) + lin[i] = a2s[ulaw2alaw(ulaw[i+12] & 0xff)]; + } + public static void linear2ulaw(short lin[],int offset,byte ulaw[],int frames) { + int i; + for (i = 0; i < frames; i++) + ulaw[i+12] = (byte)alaw2ulaw(s2a[lin[i+offset] & 0xffff]); + } + //change end +} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/RtpStreamReceiver.java --- a/src/org/sipdroid/media/RtpStreamReceiver.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/org/sipdroid/media/RtpStreamReceiver.java Sat Jan 23 22:19:43 2010 +0100 @@ -19,18 +19,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package org.sipdroid.media; +package src.org.sipdroid.media; + +import java.io.IOException; +import java.net.SocketException; -import jlibrtp.AppCallerThread; -import jlibrtp.DataFrame; -import jlibrtp.Participant; -import jlibrtp.RTPAppIntf; -import jlibrtp.RTPReceiverThread; -import jlibrtp.RTPSession; +import org.sipdroid.sipua.UserAgent; +import org.sipdroid.sipua.ui.Receiver; +import org.sipdroid.sipua.ui.Sipdroid; +import org.sipdroid.pjlib.Codec; -import org.sipdroid.media.codecs.Codec; -import org.sipdroid.net.tools.DataFramePool; -import org.sipdroid.net.tools.DatagramPool; +import src.org.sipdroid.net.RtpPacket; +import src.org.sipdroid.net.RtpSocket; +import src.org.sipdroid.net.SipdroidSocket; import android.content.ContentResolver; import android.content.Context; @@ -39,6 +40,7 @@ import android.media.AudioManager; import android.media.AudioTrack; import android.media.ToneGenerator; +import android.os.PowerManager; import android.preference.PreferenceManager; import android.provider.Settings; @@ -46,11 +48,14 @@ * RtpStreamReceiver is a generic stream receiver. It receives packets from RTP * and writes them into an OutputStream. */ -public class RtpStreamReceiver extends Thread implements RTPAppIntf{ +public class RtpStreamReceiver extends Thread { /** Whether working in debug mode. */ public static boolean DEBUG = true; + /** Payload type */ + int p_type; + /** Size of the read buffer */ public static final int BUFFER_SIZE = 1024; @@ -58,61 +63,31 @@ public static final int SO_TIMEOUT = 200; /** The RtpSocket */ - RTPSession rtpSession = null; - byte[] buffer; - - /** The codec */ - private Codec codec; - private Context mContext; - - private int frame_size; - private int codec_frame_size; - private int sampling_rate; + RtpSocket rtp_socket = null; /** Whether it is running */ boolean running; AudioManager am; ContentResolver cr; - - private int codec_divider; public static int speakermode; - - short lin[]; - short lin2[]; - int user, server, lserver, luser, cnt, todo, headroom, len, timeout = 1, seq = 0, cnt2 = 0, m = 1, - expseq, getseq, vm = 1, gap, oldvol; - boolean islate; - - Codec.Context codecCtx; - - AudioTrack track; - + /** * Constructs a RtpStreamReceiver. - * @param ctx - * @param remoteAddr * * @param output_stream * the stream sink * @param socket * the local receiver SipdroidSocket */ - public RtpStreamReceiver(Codec ci, RTPSession rtpSession, Context ctx) { - init(ci, rtpSession, ctx); + public RtpStreamReceiver(SipdroidSocket socket, int payload_type) { + init(socket); + p_type = payload_type; } - /** Inits the RtpStreamReceiver - * @param ctx - * @param remoteAddr - **/ - private void init(Codec ci, RTPSession rtpSession, Context ctx) { - this.rtpSession = rtpSession; - codec = ci; - codec_frame_size = codec.getInfo().codecFrameSize; - codec_divider = codec.getInfo().rtpSampleDivider; - frame_size = 160 * codec_divider; - sampling_rate = codec.getInfo().samplingRate; - mContext = ctx; + /** Inits the RtpStreamReceiver */ + private void init(SipdroidSocket socket) { + if (socket != null) + rtp_socket = new RtpSocket(socket); } /** Whether is running */ @@ -124,25 +99,25 @@ public void halt() { running = false; } - + public int speaker(int mode) { int old = speakermode; - + + if (Receiver.headset > 0 && mode == AudioManager.MODE_NORMAL) + return old; saveVolume(); - speakermode = mode; + setMode(speakermode = mode); restoreVolume(); return old; } double smin = 200,s; - - private int REAL_BUFFER_SIZE; public static int nearend; - + void calc(short[] lin,int off,int len) { int i,j; double sm = 30000,r; - + for (i = 0; i < len; i += 5) { j = lin[i+off]; s = 0.03*Math.abs(j) + 0.97*s; @@ -162,30 +137,58 @@ r = (double)len/100000; smin = sm*r + smin*(1-r); } - + + static void setStreamVolume(final int stream,final int vol,final int flags) { + (new Thread() { + public void run() { + AudioManager am = (AudioManager) Receiver.mContext.getSystemService(Context.AUDIO_SERVICE); + am.setStreamVolume(stream, vol, flags); + if (stream == AudioManager.STREAM_MUSIC) restored = true; + } + }).start(); + } + + static boolean restored; + void restoreVolume() { - am.setStreamVolume(AudioManager.STREAM_MUSIC, - PreferenceManager.getDefaultSharedPreferences(mContext).getInt("volume"+speakermode, - am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)* - (speakermode == AudioManager.MODE_NORMAL?4:3)/4 + switch (am.getMode()) { + case AudioManager.MODE_IN_CALL: + setStreamVolume(AudioManager.STREAM_RING,(int)( + am.getStreamMaxVolume(AudioManager.STREAM_RING)* + org.sipdroid.sipua.ui.Settings.getEarGain()), 0); + track.setStereoVolume(AudioTrack.getMaxVolume()* + org.sipdroid.sipua.ui.Settings.getEarGain() + ,AudioTrack.getMaxVolume()* + org.sipdroid.sipua.ui.Settings.getEarGain()); + break; + case AudioManager.MODE_NORMAL: + track.setStereoVolume(AudioTrack.getMaxVolume(),AudioTrack.getMaxVolume()); + break; + } + setStreamVolume(AudioManager.STREAM_MUSIC, + PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getInt("volume"+speakermode, + am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)* + (speakermode == AudioManager.MODE_NORMAL?4:3)/4 ),0); } - + void saveVolume() { - Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit(); - edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC)); - edit.commit(); + if (restored) { + Editor edit = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).edit(); + edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC)); + edit.commit(); + } } - + void saveSettings() { - if (!PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("oldvalid",false)) { + if (!PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("oldvalid",false)) { int oldvibrate = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); int oldvibrate2 = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); - if (!PreferenceManager.getDefaultSharedPreferences(mContext).contains("oldvibrate2")) + if (!PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).contains("oldvibrate2")) oldvibrate2 = AudioManager.VIBRATE_SETTING_ON; int oldpolicy = android.provider.Settings.System.getInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT); - Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit(); + Editor edit = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).edit(); edit.putInt("oldvibrate", oldvibrate); edit.putInt("oldvibrate2", oldvibrate2); edit.putInt("oldpolicy", oldpolicy); @@ -194,164 +197,287 @@ edit.commit(); } } + + public static void setMode(int mode) { + Editor edit = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).edit(); + edit.putBoolean("setmode", mode != AudioManager.MODE_NORMAL); + edit.commit(); + AudioManager am = (AudioManager) Receiver.mContext.getSystemService(Context.AUDIO_SERVICE); + am.setMode(mode); + } + + public static void restoreMode() { + if (PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("setmode",true)) { + if (Receiver.pstn_state == null || Receiver.pstn_state.equals("IDLE")) + setMode(AudioManager.MODE_NORMAL); + else { + Editor edit = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).edit(); + edit.putBoolean("setmode", false); + edit.commit(); + } + } + } - void restoreSettings() { - int oldvibrate = PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldvibrate",0); - int oldvibrate2 = PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldvibrate2",0); - int oldpolicy = PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldpolicy",0); - am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,oldvibrate); - am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,oldvibrate2); - Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY, oldpolicy); - am.setStreamVolume(AudioManager.STREAM_RING, PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldring",0), 0); - Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit(); - edit.putBoolean("oldvalid", false); - edit.commit(); + public static void restoreSettings() { + if (PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("oldvalid",true)) { + AudioManager am = (AudioManager) Receiver.mContext.getSystemService(Context.AUDIO_SERVICE); + ContentResolver cr = Receiver.mContext.getContentResolver(); + int oldvibrate = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getInt("oldvibrate",0); + int oldvibrate2 = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getInt("oldvibrate2",0); + int oldpolicy = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getInt("oldpolicy",0); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,oldvibrate); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,oldvibrate2); + Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY, oldpolicy); + setStreamVolume(AudioManager.STREAM_RING, PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getInt("oldring",0), 0); + Editor edit = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).edit(); + edit.putBoolean("oldvalid", false); + edit.commit(); + PowerManager pm = (PowerManager) Receiver.mContext.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | + PowerManager.ACQUIRE_CAUSES_WAKEUP, "Sipdroid.RtpStreamReceiver"); + wl.acquire(1000); + } + restoreMode(); } public static float good, late, lost, loss; - + public static int timeout; + + void empty() { + try { + rtp_socket.getDatagramSocket().setSoTimeout(1); + for (;;) + rtp_socket.receive(rtp_packet); + } catch (SocketException e2) { + if (!Sipdroid.release) e2.printStackTrace(); + } catch (IOException e) { + } + try { + rtp_socket.getDatagramSocket().setSoTimeout(1000); + } catch (SocketException e2) { + if (!Sipdroid.release) e2.printStackTrace(); + } + } + + RtpPacket rtp_packet; + AudioTrack track; + /** Runs it in a new Thread. */ - @Override public void run() { - REAL_BUFFER_SIZE = BUFFER_SIZE * codec_divider; - speakermode = AudioManager.MODE_IN_CALL; - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); - am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - cr = mContext.getContentResolver(); - //saveSettings(); + boolean nodata = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("nodata",false); + + if (rtp_socket == null) { + if (DEBUG) + println("ERROR: RTP socket is null"); + return; + } - Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,Settings.System.WIFI_SLEEP_POLICY_NEVER); - //am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,AudioManager.VIBRATE_SETTING_OFF); - //am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,AudioManager.VIBRATE_SETTING_OFF); - //oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC); - restoreVolume(); + byte[] buffer = new byte[BUFFER_SIZE+12]; + byte[] buffer_gsm = new byte[33+12]; + int i; + rtp_packet = new RtpPacket(buffer, 0); + + if (DEBUG) + println("Reading blocks of max " + buffer.length + " bytes"); - track = new AudioTrack(AudioManager.STREAM_MUSIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, - REAL_BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM); + running = true; + speakermode = Receiver.docked > 0?AudioManager.MODE_NORMAL:AudioManager.MODE_IN_CALL; + restored = false; + + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); + am = (AudioManager) Receiver.mContext.getSystemService(Context.AUDIO_SERVICE); + cr = Receiver.mContext.getContentResolver(); + saveSettings(); + Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,Settings.System.WIFI_SLEEP_POLICY_NEVER); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,AudioManager.VIBRATE_SETTING_OFF); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,AudioManager.VIBRATE_SETTING_OFF); + int oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC); + track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, + BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM); + short lin[] = new short[BUFFER_SIZE]; + short lin2[] = new short[BUFFER_SIZE]; + int user, server, lserver, luser, cnt, todo, headroom, len = 0, seq = 0, cnt2 = 0, m = 1, + expseq, getseq, vm = 1, gap, gseq; + timeout = 1; + boolean islate; + user = 0; + lserver = 0; + luser = -8000; + cnt = 0; + switch (p_type) { + case 3: + Codec.init(); + break; + case 0: + case 8: + G711.init(); + break; + } + ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_MUSIC,(int)(ToneGenerator.MAX_VOLUME*2*org.sipdroid.sipua.ui.Settings.getEarGain())); track.play(); - lin = new short[REAL_BUFFER_SIZE]; - lin2 = new short[REAL_BUFFER_SIZE]; - user = 0; //number of samples written - server = 0; // number of samples played - lserver = 0; // last number of samples played - luser = -sampling_rate; // last number of samples written - cnt = 0; - codecCtx = codec.initDecoder(); - System.gc(); - println("DEBUG: rtpStreamReceiver session launch"); - running = true; - AppCallerThread appCall = rtpSession.getAppCallerThrd(); - RTPReceiverThread recv = rtpSession.getRTPRecvThrd(); - DataFrame frame = null; - recv.init(); + if (Receiver.headset > 0 && Receiver.oRingtone != null) { + ToneGenerator tg2 = new ToneGenerator(AudioManager.STREAM_RING,(int)(ToneGenerator.MAX_VOLUME*2*org.sipdroid.sipua.ui.Settings.getEarGain())); + tg2.startTone(ToneGenerator.TONE_SUP_RINGTONE); + System.gc(); + tg2.stopTone(); + } else + System.gc(); while (running) { - recv.readPacketToBuffer(); - frame = appCall.getNextDataFrame(); - if (frame == null) - continue; - buffer = (frame.getPkt()[0]).getPayload(); - if (timeout != 0) { //on ecrit du blanc sur l'audiotrack - user += track.write(lin,0,REAL_BUFFER_SIZE); - user += track.write(lin,0,REAL_BUFFER_SIZE); + if (Receiver.call_state == UserAgent.UA_STATE_HOLD) { + tg.stopTone(); + track.pause(); + while (running && Receiver.call_state == UserAgent.UA_STATE_HOLD) { + try { + sleep(1000); + } catch (InterruptedException e1) { + } + } + track.play(); + System.gc(); + timeout = 1; + seq = 0; } - timeout = 0; - if (running) { - - //println("seq " + seq + " frame seq " + (frame.getPkt()[0]).getSeqNumber()); - if (seq == (frame.getPkt()[0]).getSeqNumber()) { - m++; - continue; + try { + rtp_socket.receive(rtp_packet); + if (timeout != 0) { + tg.stopTone(); + track.pause(); + user += track.write(lin2,0,BUFFER_SIZE); + user += track.write(lin2,0,BUFFER_SIZE); + track.play(); + cnt += 2*BUFFER_SIZE; + empty(); + } + timeout = 0; + } catch (IOException e) { + if (timeout == 0 && nodata) { + tg.startTone(ToneGenerator.TONE_SUP_RINGTONE); + } + rtp_socket.getDatagramSocket().disconnect(); + if (++timeout > 22) { + Receiver.engine(Receiver.mContext).rejectcall(); + break; } + } + if (running && timeout == 0) { + gseq = rtp_packet.getSequenceNumber(); + if (seq == gseq) { + m++; + continue; + } + + server = track.getPlaybackHeadPosition(); + headroom = user-server; + + if (headroom > 1500) + cnt += len; + else + cnt = 0; + + if (lserver == server) + cnt2++; + else + cnt2 = 0; - codec.decode(codecCtx, buffer, 12, codec_frame_size, lin, 0); - len = frame_size; - - if (speakermode == AudioManager.MODE_NORMAL) - calc(lin,0,len); - - server = track.getPlaybackHeadPosition(); // on récupère la position actuel de la tete de lecture - headroom = user-server; // on recalcule la différence entre la position de la tete de lecture et ce qu'on a écrit sur la piste - //println("headroom " + headroom + " user " + user + " server " + server); - if (headroom < 250 * codec_divider) { // si le headroom est trop petit, il faut rattraper le retard en écrivant du blanc/répétant ce qu'il y a à ecrire - todo = 625 * codec_divider - headroom; - //println("insert "+todo); - android.util.Log.d("RECV", "insert"); + if (cnt <= 500 || cnt2 >= 2 || headroom - 875 < len) { + switch (rtp_packet.getPayloadType()) { + case 0: + len = rtp_packet.getPayloadLength(); + G711.ulaw2linear(buffer, lin, len); + break; + case 8: + len = rtp_packet.getPayloadLength(); + G711.alaw2linear(buffer, lin, len); + break; + case 3: + for (i = 12; i < 45; i++) + buffer_gsm[i] = buffer[i]; + len = Codec.decode(buffer_gsm, lin, 0); + break; + } + + if (speakermode == AudioManager.MODE_NORMAL) + calc(lin,0,len); + } + + if (headroom < 250) { + todo = 875 - headroom; + println("insert "+todo); islate = true; - if (todo < len) - user += track.write(lin,0,todo); // on écrit le packet reçu tel quel - else - user += track.write(lin2,0,todo); // ecriture de blanc de taille 625 - headroom, avant l'écriture du packet - } else + user += track.write(lin2,0,todo); + } else islate = false; - if (headroom > 1000 * codec_divider) // si le headroom est trop grand, on calcule l'écart. - cnt += len; // on additione le nombre de sample ou il y a eu un headroom supérieur a 1000 - else - cnt = 0; - - if (lserver == server) // on compte le nombre de boucle que l'on a fait sans qu'aucun sample n'ai été joué. - cnt2++; - else - cnt2 = 0; - - if (cnt > 1000 * codec_divider && cnt2 < 2) { // si la position de la tete de lecture n'a pas bougé durant 2 tours et que le nombre de sample ou le headroom a été supérieur à 1000 est > 1000 - todo = headroom - 625 * codec_divider; - try { - //android.util.Log.d("RECV", "cut"); - sleep(20); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - user += track.write(lin,0,len); - m = 1; - seq = (frame.getPkt()[0]).getSeqNumber(); - DataFramePool.getInstance().returnFrame(frame); - //println("headroom " + headroom + " user " + user + " server " + server + " luser " + luser + " lserver " + lserver); - if (user >= luser + sampling_rate) { - /*if (am.getMode() != speakermode) { - am.setMode(speakermode); - switch (speakermode) { - case AudioManager.MODE_IN_CALL: - am.setStreamVolume(AudioManager.STREAM_RING,(int)( - am.getStreamMaxVolume(AudioManager.STREAM_RING)* - com.mbdsys.sfrdroid.ui.Settings.getEarGain()), 0); - track.setStereoVolume(AudioTrack.getMaxVolume()* - com.mbdsys.sfrdroid.ui.Settings.getEarGain() - ,AudioTrack.getMaxVolume()* - com.mbdsys.sfrdroid.ui.Settings.getEarGain()); - //running = false; - case AudioManager.MODE_NORMAL: - track.setStereoVolume(AudioTrack.getMaxVolume(),AudioTrack.getMaxVolume()); - //running = false; - } - }*/ - luser = user; - } - lserver = server; - System.arraycopy(lin, 0, lin2, 0, REAL_BUFFER_SIZE); + if (cnt > 500 && cnt2 < 2) { + todo = headroom - 875; + println("cut "+todo); + if (todo < len) + user += track.write(lin,todo,len-todo); + } else + user += track.write(lin,0,len); + + if (seq != 0) { + getseq = gseq&0xff; + expseq = ++seq&0xff; + if (m == RtpStreamSender.m) vm = m; + gap = (getseq - expseq) & 0xff; + if (gap > 0) { + if (gap > 100) gap = 1; + loss += gap; + lost += gap; + good += gap - 1; + } else { + if (m < vm) + loss++; + if (islate) + late++; + } + good++; + if (good > 100) { + good *= 0.99; + lost *= 0.99; + loss *= 0.99; + late *= 0.99; + } + } + m = 1; + seq = gseq; + + if (user >= luser + 8000 && Receiver.call_state == UserAgent.UA_STATE_INCALL) { + if (luser == -8000 || am.getMode() != speakermode) { + saveVolume(); + setMode(speakermode); + restoreVolume(); + } + luser = user; + } + lserver = server; } } track.stop(); - ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3); + saveVolume(); + setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0); + restoreSettings(); + setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0); + tg.stopTone(); + tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3); tg.startTone(ToneGenerator.TONE_PROP_PROMPT); try { - Thread.sleep(500); + sleep(500); } catch (InterruptedException e) { } tg.stopTone(); - rtpSession = null; - track = null; - codec.cleanDecoder(codecCtx); - codec = null; - println("rtp receiver terminated"); + + rtp_socket.close(); + rtp_socket = null; + + if (DEBUG) + println("rtp receiver terminated"); } /** Debug output */ - static int i = 0; private static void println(String str) { - System.out.println("RtpStreamReceiver "+ i++ +": " + str); + if (!Sipdroid.release) System.out.println("RtpStreamReceiver: " + str); } public static int byte2int(byte b) { // return (b>=0)? b : -((b^0xFF)+1); @@ -362,23 +488,4 @@ public static int byte2int(byte b1, byte b2) { return (((b1 + 0x100) % 0x100) << 8) + (b2 + 0x100) % 0x100; } - - @Override - public int frameSize(int payloadType) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void receiveData(DataFrame frame, Participant participant) { - // TODO Auto-generated method stub - - } - - @Override - public void userEvent(int type, Participant[] participant) { - // TODO Auto-generated method stub - - } - } diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/RtpStreamSender.java --- a/src/org/sipdroid/media/RtpStreamSender.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/org/sipdroid/media/RtpStreamSender.java Sat Jan 23 22:19:43 2010 +0100 @@ -19,42 +19,50 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package org.sipdroid.media; +package src.org.sipdroid.media; +import java.io.IOException; import java.io.InputStream; -import java.net.DatagramPacket; +import java.net.InetAddress; import java.util.Random; -import jlibrtp.RTPSession; -import jlibrtp.RtpPkt; +import org.sipdroid.sipua.UserAgent; +import org.sipdroid.sipua.ui.Receiver; +import org.sipdroid.sipua.ui.Settings; +import org.sipdroid.sipua.ui.Sipdroid; +import org.sipdroid.pjlib.Codec; -import org.sipdroid.media.codecs.Codec; +import src.org.sipdroid.net.RtpPacket; +import src.org.sipdroid.net.RtpSocket; +import src.org.sipdroid.net.SipdroidSocket; +import android.content.Context; import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioRecord; import android.media.MediaRecorder; +import android.preference.PreferenceManager; +import android.telephony.TelephonyManager; /** * RtpStreamSender is a generic stream sender. It takes an InputStream and sends * it through RTP. */ -public class RtpStreamSender extends Thread{ - - private static final boolean DEBUG = true; +public class RtpStreamSender extends Thread { + /** Whether working in debug mode. */ + public static boolean DEBUG = true; /** The RtpSocket */ - private RTPSession rtpSession = null; + RtpSocket rtp_socket = null; - /** Codec */ - private Codec codec; + /** Payload type */ + int p_type; - private int sampling_rate; + /** Number of frame per second */ + long frame_rate; /** Number of bytes per frame */ - private int frame_size; - - private int codec_frame_size; + int frame_size; /** * Whether it works synchronously with a local clock, or it it acts as slave @@ -62,33 +70,64 @@ */ boolean do_sync = true; + /** + * Synchronization correction value, in milliseconds. It accellarates the + * sending rate respect to the nominal value, in order to compensate program + * latencies. + */ int sync_adj = 0; /** Whether it is running */ boolean running = false; boolean muted = false; - private int codec_divider; - /** * Constructs a RtpStreamSender. * + * @param input_stream + * the stream to be sent + * @param do_sync + * whether time synchronization must be performed by the + * RtpStreamSender, or it is performed by the InputStream (e.g. + * the system audio input) + * @param payload_type + * the payload type + * @param frame_rate + * the frame rate, i.e. the number of frames that should be sent + * per second; it is used to calculate the nominal packet time + * and,in case of do_sync==true, the next departure time + * @param frame_size + * the size of the payload + * @param src_socket + * the socket used to send the RTP packet + * @param dest_addr + * the destination address + * @param dest_port + * the destination port */ - public RtpStreamSender(Codec co, RTPSession rtpSession) { - init(co, rtpSession); + public RtpStreamSender(boolean do_sync, + int payload_type, long frame_rate, int frame_size, + SipdroidSocket src_socket, String dest_addr, int dest_port) { + init(do_sync, payload_type, frame_rate, frame_size, + src_socket, dest_addr, dest_port); } /** Inits the RtpStreamSender */ - private void init(Codec co, RTPSession rtpSession) { - this.rtpSession = rtpSession; - codec = co; - sampling_rate = codec.getInfo().samplingRate; - codec_frame_size = codec.getInfo().codecFrameSize; - codec_divider = codec.getInfo().rtpSampleDivider; - frame_size = 160 * codec_divider; - rtpSession.payloadType(codec.getInfo().rtpPayloadCode); - - this.do_sync = true; + private void init(boolean do_sync, + int payload_type, long frame_rate, int frame_size, + SipdroidSocket src_socket, String dest_addr, + int dest_port) { + this.p_type = payload_type; + this.frame_rate = frame_rate; + this.frame_size = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("server","").equals("pbxes.org")? + (payload_type == 3?960:1024):frame_size; //15 + this.do_sync = do_sync; + try { + rtp_socket = new RtpSocket(src_socket, InetAddress + .getByName(dest_addr), dest_port); + } catch (Exception e) { + if (!Sipdroid.release) e.printStackTrace(); + } } /** Sets the synchronization adjustment time (in milliseconds). */ @@ -100,13 +139,13 @@ public boolean isRunning() { return running; } - + public boolean mute() { return muted = !muted; } public static int delay = 0; - + /** Stops running */ public void halt() { running = false; @@ -115,11 +154,11 @@ Random random; double smin = 200,s; int nearend; - + void calc(short[] lin,int off,int len) { int i,j; double sm = 30000,r; - + for (i = 0; i < len; i += 5) { j = lin[i+off]; s = 0.03*Math.abs(j) + 0.97*s; @@ -140,6 +179,43 @@ smin = sm*r + smin*(1-r); } + void calc1(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + lin[i+off] = (short)(j>>1); + } + } + + void calc5(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 16350) + lin[i+off] = 16350<<1; + else if (j < -16350) + lin[i+off] = -16350<<1; + else + lin[i+off] = (short)(j<<1); + } + } + + void calc10(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 8150) + lin[i+off] = 8150<<2; + else if (j < -8150) + lin[i+off] = -8150<<2; + else + lin[i+off] = (short)(j<<2); + } + } + void noise(short[] lin,int off,int len,double power) { int i,r = (int)(power*2); short ran; @@ -153,21 +229,23 @@ lin[i+off+3] = ran; } } - + public static int m; - + /** Runs it in a new Thread. */ public void run() { - if (rtpSession == null) + if (rtp_socket == null) return; - byte[] buffer = new byte[codec_frame_size + 12]; - DatagramPacket packet = new DatagramPacket(buffer, codec_frame_size + 12); - RtpPkt pkt = new RtpPkt(); - pkt.setRawPkt(buffer); - pkt.setPayloadType(codec.getInfo().rtpPayloadCode); + byte[] buffer = new byte[frame_size + 12]; + RtpPacket rtp_packet = new RtpPacket(buffer, 0); + rtp_packet.setPayloadType(p_type); int seqn = 0; long time = 0; double p = 0; + TelephonyManager tm = (TelephonyManager) Receiver.mContext.getSystemService(Context.TELEPHONY_SERVICE); + boolean improve = PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getBoolean("improve",false); + boolean useGSM = !PreferenceManager.getDefaultSharedPreferences(Receiver.mContext).getString("compression","edge").equals("never"); + int micgain = (int)(Settings.getMicGain()*10); running = true; m = 1; @@ -175,45 +253,127 @@ println("Reading blocks of " + buffer.length + " bytes"); android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); - - Codec.Context codecCtx = codec.initEncoder(); - - AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, - AudioRecord.getMinBufferSize(sampling_rate, + AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, + AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, - AudioFormat.ENCODING_PCM_16BIT)*2); - record.startRecording(); + AudioFormat.ENCODING_PCM_16BIT)*3/2); short[] lin = new short[frame_size*11]; int num,ring = 0; random = new Random(); + InputStream alerting = null; + try { + alerting = Receiver.mContext.getAssets().open("alerting"); + } catch (IOException e2) { + if (!Sipdroid.release) e2.printStackTrace(); + } + switch (p_type) { + case 3: + Codec.init(); + break; + case 0: + case 8: + G711.init(); + break; + } + record.startRecording(); while (running) { - num = record.read(lin,(ring+delay)%(frame_size*11),frame_size); - if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) { - calc(lin,(ring+delay)%(frame_size*11),num); - if (RtpStreamReceiver.nearend != 0) - noise(lin,(ring+delay)%(frame_size*11),num,p); - else if (nearend == 0) - p = 0.9*p + 0.1*s; - } - codec.encode(codecCtx, lin, ring%(frame_size*11), frame_size, buffer, 12); - ring += frame_size; - rtpSession.sendData(packet, pkt); - if (m == 2) { - rtpSession.sendData(packet, pkt); - println("retransmit"); - } - seqn++; - time += num; + if (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD) { + record.stop(); + while (running && (muted || Receiver.call_state == UserAgent.UA_STATE_HOLD)) { + try { + sleep(1000); + } catch (InterruptedException e1) { + } + } + record.startRecording(); + } + num = record.read(lin,(ring+delay)%(frame_size*11),frame_size); + + if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) { + calc(lin,(ring+delay)%(frame_size*11),num); + if (RtpStreamReceiver.nearend != 0) + noise(lin,(ring+delay)%(frame_size*11),num,p); + else if (nearend == 0) + p = 0.9*p + 0.1*s; + } else switch (micgain) { + case 1: + calc1(lin,(ring+delay)%(frame_size*11),num); + break; + case 5: + calc5(lin,(ring+delay)%(frame_size*11),num); + break; + case 10: + calc10(lin,(ring+delay)%(frame_size*11),num); + break; + } + if (Receiver.call_state != UserAgent.UA_STATE_INCALL && alerting != null) { + try { + if (alerting.available() < num) + alerting.reset(); + alerting.read(buffer,12,num); + } catch (IOException e) { + if (!Sipdroid.release) e.printStackTrace(); + } + switch (p_type) {// have to add ulaw case? + case 3: + G711.alaw2linear(buffer, lin, num); + num = Codec.encode(lin, 0, buffer, num); + break; + case 0: + G711.alaw2linear(buffer, lin, num); + G711.linear2ulaw(lin, 0, buffer, num); + break; + } + } else { + switch (p_type) { + case 3: + num = Codec.encode(lin, ring%(frame_size*11), buffer, num); + break; + case 0: + G711.linear2ulaw(lin, ring%(frame_size*11), buffer, num); + break; + case 8: + G711.linear2alaw(lin, ring%(frame_size*11), buffer, num); + break; + } + } + ring += frame_size; + rtp_packet.setSequenceNumber(seqn++); + rtp_packet.setTimestamp(time); + rtp_packet.setPayloadLength(num); + try { + rtp_socket.send(rtp_packet); + if (m == 2) + rtp_socket.send(rtp_packet); + } catch (IOException e) { + } + time += frame_size; + if (improve && RtpStreamReceiver.good != 0 && + RtpStreamReceiver.loss/RtpStreamReceiver.good > 0.01 && + (Receiver.on_wlan || tm.getNetworkType() != TelephonyManager.NETWORK_TYPE_EDGE)) + m = 2; + else + m = 1; + if (useGSM && p_type == 8 && !Receiver.on_wlan && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE) { + rtp_packet.setPayloadType(p_type = 3); + if (frame_size == 1024) { + frame_size = 960; + ring = 0; + } + } } record.stop(); - rtpSession = null; - codec.cleanEncoder(codecCtx); + + rtp_socket.close(); + rtp_socket = null; + if (DEBUG) println("rtp sender terminated"); } /** Debug output */ private static void println(String str) { - android.util.Log.d("DEBUG","RtpStreamSender: " + str); + if (!Sipdroid.release) System.out.println("RtpStreamSender: " + str); } -} + +} \ No newline at end of file diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/Codec.java --- a/src/org/sipdroid/media/codecs/Codec.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -package org.sipdroid.media.codecs; - -public abstract class Codec { - - public abstract class Context { - }; - - public abstract Context initEncoder(); - public abstract Context initDecoder(); - public abstract void cleanEncoder(Context ctx); - public abstract void cleanDecoder(Context ctx); - - - public abstract int encode(Context ctx, short[] insample, int inoffset, int size, byte[] outdata, int outoffset); - public abstract int decode(Context ctx, byte[] indata, int inoffset, int size, short[] outsample, int outoffset); - - public abstract CodecInfo getInfo(); - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/CodecInfo.java --- a/src/org/sipdroid/media/codecs/CodecInfo.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -package org.sipdroid.media.codecs; - -/** - * @author vadim - * - */ -public class CodecInfo { - /** - * String to show in config dialog - */ - public String displayName; - /** - * codec spec string to use in SDP - */ - public String rtpPayloadName; - /** - * prefered RTP payload code - */ - public int rtpPayloadCode; - /** - * sampling rate for this codec - */ - public int samplingRate; - /** - * divider for sampling rate to use when computing rtp timestamp - */ - public int rtpSampleDivider; - /** - * minimum frameSize in milliseconds - */ - public int minFrameTimeMsecs; - /** - * codec description to display in configuration dialog - */ - public String description; - - /** - * codec frame size - */ - public int codecFrameSize; - - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/CodecManager.java --- a/src/org/sipdroid/media/codecs/CodecManager.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/** - * - */ -package org.sipdroid.media.codecs; - -import java.util.LinkedList; - -/** - * @author vadim - * - */ -public class CodecManager { - - public static void load() { - GSM.load(); - G711.load(); - G722.load(); - } - - public static LinkedList audioCodecs = new LinkedList(); - - public static Codec getCodecByDisplayName(String cn) { - - for (Codec c : audioCodecs) { - if (c.getInfo().displayName.equals(cn)) - return c; - } - - return null; - } - - public static Codec getCodecByRtpName(String cn) { - - for (Codec c : audioCodecs) { - if (c.getInfo().rtpPayloadName.equals(cn)) - return c; - } - - return null; - } - - - public static void registerAudioCodec(Codec c) { - audioCodecs.addLast(c); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/G711.java --- a/src/org/sipdroid/media/codecs/G711.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -package org.sipdroid.media.codecs; - -/** - * G.711 codec. This class provides methods for u-law, A-law and linear PCM - * conversions. - */ -public class G711 extends Codec { - /* - * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische - * Universitaet Berlin. See the accompanying file "COPYRIGHT" for - * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. - */ - public static final CodecInfo mCodecInfo = new CodecInfo(); - - static { - mCodecInfo.displayName = "aLaw"; - mCodecInfo.rtpPayloadName = "PCMA"; - mCodecInfo.description = "G711 aLaw codec"; - mCodecInfo.rtpPayloadCode = 8; - mCodecInfo.samplingRate = 8000; - mCodecInfo.rtpSampleDivider = 1; - mCodecInfo.minFrameTimeMsecs = 20; - mCodecInfo.codecFrameSize = 160; - CodecManager.registerAudioCodec(new G711()); - } - - private static final int[] _a2s = { - - 60032, 60288, 59520, 59776, 61056, 61312, 60544, 60800, - 57984, 58240, 57472, 57728, 59008, 59264, 58496, 58752, - 62784, 62912, 62528, 62656, 63296, 63424, 63040, 63168, - 61760, 61888, 61504, 61632, 62272, 62400, 62016, 62144, - 43520, 44544, 41472, 42496, 47616, 48640, 45568, 46592, - 35328, 36352, 33280, 34304, 39424, 40448, 37376, 38400, - 54528, 55040, 53504, 54016, 56576, 57088, 55552, 56064, - 50432, 50944, 49408, 49920, 52480, 52992, 51456, 51968, - 65192, 65208, 65160, 65176, 65256, 65272, 65224, 65240, - 65064, 65080, 65032, 65048, 65128, 65144, 65096, 65112, - 65448, 65464, 65416, 65432, 65512, 65528, 65480, 65496, - 65320, 65336, 65288, 65304, 65384, 65400, 65352, 65368, - 64160, 64224, 64032, 64096, 64416, 64480, 64288, 64352, - 63648, 63712, 63520, 63584, 63904, 63968, 63776, 63840, - 64848, 64880, 64784, 64816, 64976, 65008, 64912, 64944, - 64592, 64624, 64528, 64560, 64720, 64752, 64656, 64688, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 - - }; - - private static final int[] _s2a = { - - 213,212,215,214,209,208,211,210,221,220,223,222,217,216,219,218, - 197,196,199,198,193,192,195,194,205,204,207,206,201,200,203,202, - 245,245,244,244,247,247,246,246,241,241,240,240,243,243,242,242, - 253,253,252,252,255,255,254,254,249,249,248,248,251,251,250,250, - 229,229,229,229,228,228,228,228,231,231,231,231,230,230,230,230, - 225,225,225,225,224,224,224,224,227,227,227,227,226,226,226,226, - 237,237,237,237,236,236,236,236,239,239,239,239,238,238,238,238, - 233,233,233,233,232,232,232,232,235,235,235,235,234,234,234,234, - 149,149,149,149,149,149,149,149,148,148,148,148,148,148,148,148, - 151,151,151,151,151,151,151,151,150,150,150,150,150,150,150,150, - 145,145,145,145,145,145,145,145,144,144,144,144,144,144,144,144, - 147,147,147,147,147,147,147,147,146,146,146,146,146,146,146,146, - 157,157,157,157,157,157,157,157,156,156,156,156,156,156,156,156, - 159,159,159,159,159,159,159,159,158,158,158,158,158,158,158,158, - 153,153,153,153,153,153,153,153,152,152,152,152,152,152,152,152, - 155,155,155,155,155,155,155,155,154,154,154,154,154,154,154,154, - 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, - 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, - 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, - 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, - 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, - 130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, - 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, - 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, - 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, - 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, - 137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, - 136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, - 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, - 138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, - 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, - 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, - 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, - 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, - 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, - 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, - 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, - 182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, - 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, - 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, - 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, - 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, - 179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, - 179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, - 178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, - 178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, - 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, - 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, - 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, - 188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, - 191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, - 191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, - 190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, - 190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, - 185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, - 185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, - 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, - 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, - 187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, - 187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, - 186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, - 186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, - 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, - 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, - 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, - 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, - 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, - 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, - 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, - 164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, - 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, - 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, - 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, - 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, - 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, - 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, - 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, - 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, - 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, - 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, - 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, - 161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, - 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, - 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, - 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, - 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, - 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, - 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, - 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, - 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, - 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, - 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, - 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, - 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, - 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, - 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, - 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, - 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, - 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, - 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, - 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, - 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, - 175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, - 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, - 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, - 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, - 174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, - 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, - 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, - 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, - 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, - 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, - 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, - 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, - 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, - 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, - 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, - 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, - 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, - 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, - 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, - 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, - 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, - 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, - 106,106,106,106,107,107,107,107,104,104,104,104,105,105,105,105, - 110,110,110,110,111,111,111,111,108,108,108,108,109,109,109,109, - 98, 98, 98, 98, 99, 99, 99, 99, 96, 96, 96, 96, 97, 97, 97, 97, - 102,102,102,102,103,103,103,103,100,100,100,100,101,101,101,101, - 122,122,123,123,120,120,121,121,126,126,127,127,124,124,125,125, - 114,114,115,115,112,112,113,113,118,118,119,119,116,116,117,117, - 74, 75, 72, 73, 78, 79, 76, 77, 66, 67, 64, 65, 70, 71, 68, 69, - 90, 91, 88, 89, 94, 95, 92, 93, 82, 83, 80, 81, 86, 87, 84, 85 - }; - - - public class G711Context extends Context { - public final short[] a2s = new short[256]; - public final byte[] s2a = new byte[65536]; - } - - public void init(G711Context ctx) { - int i; - for (i = 0; i < 256; i++) - ctx.a2s[i] = (short)_a2s[i]; - for (i = 0; i < 65536; i++) - ctx.s2a[i] = (byte)_s2a[i >> 4]; - } - - private void alaw2linear(G711Context ctx, byte alaw[], int inoffset, int size, short lin[], int outoffset) { - int i; - for (i = 0; i < size; i++) - lin[i + outoffset] = ctx.a2s[alaw[i + inoffset] & 0xff]; - } - - private void linear2alaw(G711Context ctx, short lin[], int inoffset, byte alaw[], int outoffset, int size) { - int i; - for (i = 0; i < size; i++) - alaw[i + outoffset] = ctx.s2a[lin[i + inoffset] & 0xffff]; - } - - @Override - public Context initDecoder() { - G711Context ctx = new G711Context(); - init(ctx); - return ctx; - } - - @Override - public Context initEncoder() { - G711Context ctx = new G711Context(); - init(ctx); - return ctx; - } - - @Override - public void cleanDecoder(Context ctx) { - } - - @Override - public void cleanEncoder(Context ctx) { - } - - @Override - public int decode(Context ctx, byte[] indata, int inoffset, int size, - short[] outsample, int outoffset) { - alaw2linear((G711Context) ctx, indata, inoffset, size, outsample, outoffset); - return size; - } - - @Override - public int encode(Context ctx, short[] insample, int inoffset, int size, - byte[] outdata, int outoffset) { - linear2alaw((G711Context) ctx, insample, inoffset, outdata, outoffset, size); - return 0; - } - - @Override - public CodecInfo getInfo() { - return mCodecInfo; - } - - static public void load(){ - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/G722.java --- a/src/org/sipdroid/media/codecs/G722.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -package org.sipdroid.media.codecs; - -public class G722 extends Codec { - - public static final CodecInfo mCodecInfo = new CodecInfo(); - - static { - System.loadLibrary("g722"); - mCodecInfo.displayName = "G722"; - mCodecInfo.rtpPayloadName = "G722"; - mCodecInfo.description = "G722 16kHz codec"; - mCodecInfo.rtpPayloadCode = 9; - mCodecInfo.samplingRate = 16000; - mCodecInfo.rtpSampleDivider = 2; - mCodecInfo.minFrameTimeMsecs = 20; - mCodecInfo.codecFrameSize = 160; - CodecManager.registerAudioCodec(new G722()); - } - - public class G722Context extends Context { - public long ctx; - } - - @Override - public Context initDecoder() { - G722Context decoderCtx = new G722Context(); - decoderCtx.ctx = G722JNI.decodeInit(decoderCtx.ctx, mCodecInfo.codecFrameSize, 0); - return decoderCtx; - } - - @Override - public Context initEncoder() { - G722Context encoderCtx = new G722Context(); - encoderCtx.ctx = G722JNI.encodeInit(encoderCtx.ctx, mCodecInfo.codecFrameSize, 0); - return encoderCtx; - } - - @Override - public void cleanDecoder(Context ctx) { - G722JNI.decodeRelease(((G722Context)ctx).ctx); - } - - @Override - public void cleanEncoder(Context ctx) { - G722JNI.encodeRelease(((G722Context)ctx).ctx); - } - - @Override - public int decode(Context ctx, byte[] indata, int inoffset, int size, - short[] outsample, int outoffset) { - return G722JNI.decode(((G722Context)ctx).ctx, indata, inoffset, outsample, outoffset, size); - } - - @Override - public int encode(Context ctx, short[] insample, int inoffset, int size, - byte[] outdata, int outoffset) { - G722JNI.encode(((G722Context)ctx).ctx, insample, inoffset, outdata, outoffset, size); - return size; - } - - @Override - public CodecInfo getInfo() { - return mCodecInfo; - } - - static public void load(){ - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/G722JNI.java --- a/src/org/sipdroid/media/codecs/G722JNI.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -package org.sipdroid.media.codecs; - -public class G722JNI { - public static native long encodeInit(long g722State, int rate, int options); - public static native int encodeRelease(long g722State); - public static native int encode(long g722State, short[] signal, long srcPos, byte[] g722Byte, long destPos, int len); - public static native long decodeInit(long g722State, int rate, int options); - public static native int decodeRelease(long g722State); - public static native int decode(long g722State, byte[] g722Byte, long srcPos, short[] signal, long destPos, int len); -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/GSM.java --- a/src/org/sipdroid/media/codecs/GSM.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -package org.sipdroid.media.codecs; - -public class GSM extends Codec { - - public static final CodecInfo mCodecInfo = new CodecInfo(); - - static { - System.loadLibrary("gsm"); - mCodecInfo.displayName = "GSM"; - mCodecInfo.rtpPayloadName = "GSM"; - mCodecInfo.description = "GSM Full Rate codec"; - mCodecInfo.rtpPayloadCode = 3; - mCodecInfo.samplingRate = 8000; - mCodecInfo.rtpSampleDivider = 1; - mCodecInfo.minFrameTimeMsecs = 20; - mCodecInfo.codecFrameSize = 33; - CodecManager.registerAudioCodec(new GSM()); - } - - public class GSMContext extends Context { - public long ctx; - } - - @Override - public Context initDecoder() { - GSMContext decoderCtx = new GSMContext(); - decoderCtx.ctx = GSMJNI.create(); - return decoderCtx; - } - - @Override - public Context initEncoder() { - GSMContext encoderCtx = new GSMContext(); - encoderCtx.ctx = GSMJNI.create(); - return encoderCtx; - } - - @Override - public void cleanDecoder(Context ctx) { - GSMJNI.destroy(((GSMContext)ctx).ctx); - } - - @Override - public void cleanEncoder(Context ctx) { - GSMJNI.destroy(((GSMContext)ctx).ctx); - } - - @Override - public int decode(Context ctx, byte[] indata, int inoffset, int size, - short[] outsample, int outoffset) { - return GSMJNI.decode(((GSMContext)ctx).ctx, indata, inoffset, outsample, outoffset); - } - - @Override - public int encode(Context ctx, short[] insample, int inoffset, int size, - byte[] outdata, int outoffset) { - GSMJNI.encode(((GSMContext)ctx).ctx, insample, inoffset, outdata, outoffset); - return size; - } - - @Override - public CodecInfo getInfo() { - return mCodecInfo; - } - - static public void load(){ - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/media/codecs/GSMJNI.java --- a/src/org/sipdroid/media/codecs/GSMJNI.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -package org.sipdroid.media.codecs; - -public class GSMJNI { - public static native long create(); - public static native void destroy(long gsm); - public static native int decode(long gsm, byte[] gsmByte, long srcPos, short[] signal, long destPos); - public static native void encode(long gsm, short[] signal, long srcPos, byte[] gsmByte, long destPos); -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/RtpPacket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/RtpPacket.java Sat Jan 23 22:19:43 2010 +0100 @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package src.org.sipdroid.net; + +import org.zoolu.tools.Random; + +/** + * RtpPacket implements a RTP packet. + */ +public class RtpPacket { + /* RTP packet buffer containing both the RTP header and payload */ + byte[] packet; + + /* RTP packet length */ + int packet_len; + + /* RTP header length */ + // int header_len; + /** Gets the RTP packet */ + public byte[] getPacket() { + return packet; + } + + /** Gets the RTP packet length */ + public int getLength() { + return packet_len; + } + + /** Gets the RTP header length */ + public int getHeaderLength() { + if (packet_len >= 12) + return 12 + 4 * getCscrCount(); + else + return packet_len; // broken packet + } + + /** Gets the RTP header length */ + public int getPayloadLength() { + if (packet_len >= 12) + return packet_len - getHeaderLength(); + else + return 0; // broken packet + } + + /** Sets the RTP payload length */ + public void setPayloadLength(int len) { + packet_len = getHeaderLength() + len; + } + + // version (V): 2 bits + // padding (P): 1 bit + // extension (X): 1 bit + // CSRC count (CC): 4 bits + // marker (M): 1 bit + // payload type (PT): 7 bits + // sequence number: 16 bits + // timestamp: 32 bits + // SSRC: 32 bits + // CSRC list: 0 to 15 items, 32 bits each + + /** Gets the version (V) */ + public int getVersion() { + if (packet_len >= 12) + return (packet[0] >> 6 & 0x03); + else + return 0; // broken packet + } + + /** Sets the version (V) */ + public void setVersion(int v) { + if (packet_len >= 12) + packet[0] = (byte) ((packet[0] & 0x3F) | ((v & 0x03) << 6)); + } + + /** Whether has padding (P) */ + public boolean hasPadding() { + if (packet_len >= 12) + return getBit(packet[0], 5); + else + return false; // broken packet + } + + /** Set padding (P) */ + public void setPadding(boolean p) { + if (packet_len >= 12) + packet[0] = setBit(p, packet[0], 5); + } + + /** Whether has extension (X) */ + public boolean hasExtension() { + if (packet_len >= 12) + return getBit(packet[0], 4); + else + return false; // broken packet + } + + /** Set extension (X) */ + public void setExtension(boolean x) { + if (packet_len >= 12) + packet[0] = setBit(x, packet[0], 4); + } + + /** Gets the CSCR count (CC) */ + public int getCscrCount() { + if (packet_len >= 12) + return (packet[0] & 0x0F); + else + return 0; // broken packet + } + + /** Whether has marker (M) */ + public boolean hasMarker() { + if (packet_len >= 12) + return getBit(packet[1], 7); + else + return false; // broken packet + } + + /** Set marker (M) */ + public void setMarker(boolean m) { + if (packet_len >= 12) + packet[1] = setBit(m, packet[1], 7); + } + + /** Gets the payload type (PT) */ + public int getPayloadType() { + if (packet_len >= 12) + return (packet[1] & 0x7F); + else + return -1; // broken packet + } + + /** Sets the payload type (PT) */ + public void setPayloadType(int pt) { + if (packet_len >= 12) + packet[1] = (byte) ((packet[1] & 0x80) | (pt & 0x7F)); + } + + /** Gets the sequence number */ + public int getSequenceNumber() { + if (packet_len >= 12) + return getInt(packet, 2, 4); + else + return 0; // broken packet + } + + /** Sets the sequence number */ + public void setSequenceNumber(int sn) { + if (packet_len >= 12) + setInt(sn, packet, 2, 4); + } + + /** Gets the timestamp */ + public long getTimestamp() { + if (packet_len >= 12) + return getLong(packet, 4, 8); + else + return 0; // broken packet + } + + /** Sets the timestamp */ + public void setTimestamp(long timestamp) { + if (packet_len >= 12) + setLong(timestamp, packet, 4, 8); + } + + /** Gets the SSCR */ + public long getSscr() { + if (packet_len >= 12) + return getLong(packet, 8, 12); + else + return 0; // broken packet + } + + /** Sets the SSCR */ + public void setSscr(long ssrc) { + if (packet_len >= 12) + setLong(ssrc, packet, 8, 12); + } + + /** Gets the CSCR list */ + public long[] getCscrList() { + int cc = getCscrCount(); + long[] cscr = new long[cc]; + for (int i = 0; i < cc; i++) + cscr[i] = getLong(packet, 12 + 4 * i, 16 + 4 * i); + return cscr; + } + + /** Sets the CSCR list */ + public void setCscrList(long[] cscr) { + if (packet_len >= 12) { + int cc = cscr.length; + if (cc > 15) + cc = 15; + packet[0] = (byte) (((packet[0] >> 4) << 4) + cc); + cscr = new long[cc]; + for (int i = 0; i < cc; i++) + setLong(cscr[i], packet, 12 + 4 * i, 16 + 4 * i); + // header_len=12+4*cc; + } + } + + /** Sets the payload */ + public void setPayload(byte[] payload, int len) { + if (packet_len >= 12) { + int header_len = getHeaderLength(); + for (int i = 0; i < len; i++) + packet[header_len + i] = payload[i]; + packet_len = header_len + len; + } + } + + /** Gets the payload */ + public byte[] getPayload() { + int header_len = getHeaderLength(); + int len = packet_len - header_len; + byte[] payload = new byte[len]; + for (int i = 0; i < len; i++) + payload[i] = packet[header_len + i]; + return payload; + } + + /** Creates a new RTP packet */ + public RtpPacket(byte[] buffer, int packet_length) { + packet = buffer; + packet_len = packet_length; + if (packet_len < 12) + packet_len = 12; + init(0x0F); + } + + /** init the RTP packet header (only PT) */ + public void init(int ptype) { + init(ptype, Random.nextLong()); + } + + /** init the RTP packet header (PT and SSCR) */ + public void init(int ptype, long sscr) { + init(ptype, Random.nextInt(), Random.nextLong(), sscr); + } + + /** init the RTP packet header (PT, SQN, TimeStamp, SSCR) */ + public void init(int ptype, int seqn, long timestamp, long sscr) { + setVersion(2); + setPayloadType(ptype); + setSequenceNumber(seqn); + setTimestamp(timestamp); + setSscr(sscr); + } + + // *********************** Private and Static *********************** + + /** Gets int value */ + private static int getInt(byte b) { + return ((int) b + 256) % 256; + } + + /** Gets long value */ + private static long getLong(byte[] data, int begin, int end) { + long n = 0; + for (; begin < end; begin++) { + n <<= 8; + n += data[begin]; + } + return n; + } + + /** Sets long value */ + private static void setLong(long n, byte[] data, int begin, int end) { + for (end--; end >= begin; end--) { + data[end] = (byte) (n % 256); + n >>= 8; + } + } + + /** Gets Int value */ + private static int getInt(byte[] data, int begin, int end) { + return (int) getLong(data, begin, end); + } + + /** Sets Int value */ + private static void setInt(int n, byte[] data, int begin, int end) { + setLong(n, data, begin, end); + } + + /** Gets bit value */ + private static boolean getBit(byte b, int bit) { + return (b >> bit) == 1; + } + + /** Sets bit value */ + private static byte setBit(boolean value, byte b, int bit) { + if (value) + return (byte) (b | (1 << bit)); + else + return (byte) ((b | (1 << bit)) ^ (1 << bit)); + } +} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/RtpSocket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/RtpSocket.java Sat Jan 23 22:19:43 2010 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package src.org.sipdroid.net; + +import java.net.InetAddress; +import java.net.DatagramPacket; +import java.io.IOException; + + + +/** + * RtpSocket implements a RTP socket for receiving and sending RTP packets. + *

+ * RtpSocket is associated to a DatagramSocket that is used to send and/or + * receive RtpPackets. + */ +public class RtpSocket { + /** UDP socket */ + SipdroidSocket socket; + DatagramPacket datagram; + + /** Remote address */ + InetAddress r_addr; + + /** Remote port */ + int r_port; + + /** Creates a new RTP socket (only receiver) */ + public RtpSocket(SipdroidSocket datagram_socket) { + socket = datagram_socket; + r_addr = null; + r_port = 0; + datagram = new DatagramPacket(new byte[1],1); + } + + /** Creates a new RTP socket (sender and receiver) */ + public RtpSocket(SipdroidSocket datagram_socket, + InetAddress remote_address, int remote_port) { + socket = datagram_socket; + r_addr = remote_address; + r_port = remote_port; + datagram = new DatagramPacket(new byte[1],1); + } + + /** Returns the RTP SipdroidSocket */ + public SipdroidSocket getDatagramSocket() { + return socket; + } + + /** Receives a RTP packet from this socket */ + public void receive(RtpPacket rtpp) throws IOException { + datagram.setData(rtpp.packet); + datagram.setLength(rtpp.packet.length); + socket.receive(datagram); + if (!socket.isConnected()) + socket.connect(datagram.getAddress(),datagram.getPort()); + rtpp.packet_len = datagram.getLength(); + } + + /** Sends a RTP packet from this socket */ + public void send(RtpPacket rtpp) throws IOException { + datagram.setData(rtpp.packet); + datagram.setLength(rtpp.packet_len); + datagram.setAddress(r_addr); + datagram.setPort(r_port); + socket.send(datagram); + } + + /** Closes this socket */ + public void close() { // socket.close(); + } + +} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/SipdroidSocket.java --- a/src/org/sipdroid/net/SipdroidSocket.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/org/sipdroid/net/SipdroidSocket.java Sat Jan 23 22:19:43 2010 +0100 @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package org.sipdroid.net; +package src.org.sipdroid.net; import java.io.IOException; import java.net.DatagramPacket; @@ -79,8 +79,11 @@ } static { + try { System.loadLibrary("OSNetworkSystem"); OSNetworkSystem.getOSNetworkSystem().oneTimeInitialization(true); SipdroidSocket.loaded = true; + } catch (Throwable e) { + } } } diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/impl/OSNetworkSystem.java --- a/src/org/sipdroid/net/impl/OSNetworkSystem.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/org/sipdroid/net/impl/OSNetworkSystem.java Sat Jan 23 22:19:43 2010 +0100 @@ -22,7 +22,7 @@ // address length was changed from long to int for performance reasons. // END android-note -package org.sipdroid.net.impl; +package src.org.sipdroid.net.impl; import java.io.FileDescriptor; import java.io.IOException; diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java --- a/src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java Sat Jan 23 21:48:58 2010 +0100 +++ b/src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java Sat Jan 23 22:19:43 2010 +0100 @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package org.sipdroid.net.impl; +package src.org.sipdroid.net.impl; import java.io.FileDescriptor; import java.io.IOException; @@ -76,7 +76,7 @@ private OSNetworkSystem netImpl = OSNetworkSystem.getOSNetworkSystem(); - private volatile boolean isNativeConnected = false; + private volatile boolean isNativeConnected; public int receiveTimeout; diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/tools/DataFramePool.java --- a/src/org/sipdroid/net/tools/DataFramePool.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -package org.sipdroid.net.tools; - -import jlibrtp.DataFrame; - -public class DataFramePool extends ObjectPool { - - private static DataFramePool instance = null; - public static DataFramePool getInstance() { - if(instance == null) { - instance = new DataFramePool(20); - } - return instance; - } - - public static void removeInstance() { - instance = null; - } - - protected DataFramePool(int nbObject) { - super(nbObject); - for(int i = 0; i < nbObject; ++i) { - checkIn(create()); - } - } - - @Override - Object create() { - return new DataFrame(); - } - - @Override - boolean validate(Object o) { - return true; - } - - public DataFrame borrowFrame() { - return (DataFrame) super.checkOut(); - } - - public void returnFrame(DataFrame o) { - o.release(); - super.checkIn(o); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/tools/DatagramPool.java --- a/src/org/sipdroid/net/tools/DatagramPool.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -package org.sipdroid.net.tools; - -import java.net.DatagramPacket; - -public class DatagramPool extends ObjectPool { - - private static DatagramPool instance = null; - public static DatagramPool getInstance() { - if(instance == null) { - instance = new DatagramPool(20); - } - return instance; - } - - public static void removeInstance() { - instance = null; - } - - protected DatagramPool(int nbDatagram) { - super(nbDatagram); - for(int i = 0; i < nbDatagram; ++i) { - checkIn(create()); - } - } - - @Override - Object create() { - byte[] rawPkt = new byte[1500]; - DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length); - return packet; - } - - @Override - boolean validate(Object o) { - return true; - } - - public DatagramPacket borrowPacket() { - return (DatagramPacket) super.checkOut(); - } - - public void returnPacket(DatagramPacket packet) { - super.checkIn(packet); - } -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/tools/GenericPool.java --- a/src/org/sipdroid/net/tools/GenericPool.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -package org.sipdroid.net.tools; - -public class GenericPool extends ObjectPool { - - public GenericPool(int size) { - super(size); - for(int i = 0; i < size; ++i) { - checkIn(create()); - } - } - - @Override - protected E create() { - return (E)new Object(); - } - - @Override - protected boolean validate(Object o) { - // TODO Auto-generated method stub - return false; - } - - public E borrowItem() { - return (E) super.checkOut(); - } - - public void returnItem(E o) { - super.checkIn(o); - } - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/tools/ObjectPool.java --- a/src/org/sipdroid/net/tools/ObjectPool.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -package org.sipdroid.net.tools; - -import java.util.ArrayList; - -public abstract class ObjectPool { - private ArrayList locked, unlocked; - - ObjectPool(int size){ - locked = new ArrayList(size); - unlocked = new ArrayList(size); - } - - public int getPoolSize() { - return locked.size() + unlocked.size(); - } - - abstract Object create(); - abstract boolean validate( Object o ); - synchronized Object checkOut(){ - if(unlocked.size() > 0){ - Object cur = unlocked.get(0); - unlocked.remove(cur); - locked.add(cur); - return(cur); - } - // no objects available, create a new one - Object o = create(); - locked.add(o); - return(o); - } - - synchronized void checkIn( Object o ) { - locked.remove( o ); - unlocked.add(o); - } - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/tools/PktBufNodePool.java --- a/src/org/sipdroid/net/tools/PktBufNodePool.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -package org.sipdroid.net.tools; - -import jlibrtp.PktBufNode; - -public class PktBufNodePool extends ObjectPool { - - private static PktBufNodePool instance = null; - public static PktBufNodePool getInstance() { - if(instance == null) { - instance = new PktBufNodePool(20); - } - return instance; - } - - public static void removeInstance() { - instance = null; - } - - protected PktBufNodePool(int nbObject) { - super(nbObject); - for(int i = 0; i < nbObject; ++i) { - checkIn(create()); - } - } - - @Override - Object create() { - return new PktBufNode(); - } - - @Override - boolean validate(Object o) { - return true; - } - - public PktBufNode borrowBufNode() { - return (PktBufNode) super.checkOut(); - } - - public void returnBufNode(PktBufNode o) { - super.checkIn(o); - } - -} diff -r f5a5d9237d69 -r e8d6255306f8 src/org/sipdroid/net/tools/RtpPktPool.java --- a/src/org/sipdroid/net/tools/RtpPktPool.java Sat Jan 23 21:48:58 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -package org.sipdroid.net.tools; - -import jlibrtp.RtpPkt; - -public class RtpPktPool extends ObjectPool { - - private static RtpPktPool instance = null; - public static RtpPktPool getInstance() { - if(instance == null) { - instance = new RtpPktPool(20); - } - return instance; - } - - public static void removeInstance() { - instance = null; - } - - protected RtpPktPool(int nbObject) { - super(nbObject); - for(int i = 0; i < nbObject; ++i) { - checkIn(create()); - } - } - - @Override - Object create() { - return new RtpPkt(); - } - - @Override - boolean validate(Object o) { - return true; - } - - public RtpPkt borrowPkt() { - return (RtpPkt) super.checkOut(); - } - - public void returnPkt(RtpPkt o) { - super.checkIn(o); - } - -}