+ *
+ * @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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/RtcpPktRR.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktRR.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,235 @@
+/**
+ * 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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/RtcpPktRTPFB.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktRTPFB.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,165 @@
+/**
+ * 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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/RtcpPktSDES.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktSDES.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,308 @@
+/**
+ * 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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/RtcpPktSR.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktSR.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,190 @@
+/**
+ * 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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/RtpPkt.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtpPkt.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,465 @@
+/**
+ * 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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/StaticProcs.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/StaticProcs.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,298 @@
+/**
+ * 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 047b5e2b9904 -r af3a788344f9 src/jlibrtp/package.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/package.html Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,22 @@
+
+
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/RtpStreamReceiver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/RtpStreamReceiver.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,391 @@
+/*
+ * 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 org.sipdroid.media;
+
+import jlibrtp.AppCallerThread;
+import jlibrtp.DataFrame;
+import jlibrtp.Participant;
+import jlibrtp.RTPAppIntf;
+import jlibrtp.RTPReceiverThread;
+import jlibrtp.RTPSession;
+
+import org.sipdroid.media.codecs.Codec;
+import org.sipdroid.net.tools.DataFramePool;
+import org.sipdroid.net.tools.DatagramPool;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences.Editor;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.ToneGenerator;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+
+/**
+ * RtpStreamReceiver is a generic stream receiver. It receives packets from RTP
+ * and writes them into an OutputStream.
+ */
+public class RtpStreamReceiver extends Thread implements RTPAppIntf{
+
+ /** Whether working in debug mode. */
+ public static boolean DEBUG = true;
+
+ /** Size of the read buffer */
+ public static final int BUFFER_SIZE = 1024;
+
+ /** Maximum blocking time, spent waiting for reading new bytes [milliseconds] */
+ public static final int SO_TIMEOUT = 200;
+
+ /** The RtpSocket */
+ //RtpSocket rtp_socket = null;
+ 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;
+
+ /** 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);
+ }
+
+ /** 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;
+ }
+
+ /** Whether is running */
+ public boolean isRunning() {
+ return running;
+ }
+
+ /** Stops running */
+ public void halt() {
+ running = false;
+ }
+
+ public int speaker(int mode) {
+ int old = speakermode;
+
+ saveVolume();
+ 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;
+ if (s < sm) sm = s;
+ if (s > smin) nearend = 3000/5;
+ else if (nearend > 0) nearend--;
+ }
+ for (i = 0; i < len; i++) {
+ j = lin[i+off];
+ if (j > 6550)
+ lin[i+off] = 6550*5;
+ else if (j < -6550)
+ lin[i+off] = -6550*5;
+ else
+ lin[i+off] = (short)(j*5);
+ }
+ r = (double)len/100000;
+ smin = sm*r + smin*(1-r);
+ }
+
+ 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
+ ),0);
+ }
+
+ void saveVolume() {
+ Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+ edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC));
+ edit.commit();
+ }
+
+ void saveSettings() {
+ if (!PreferenceManager.getDefaultSharedPreferences(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"))
+ 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();
+ edit.putInt("oldvibrate", oldvibrate);
+ edit.putInt("oldvibrate2", oldvibrate2);
+ edit.putInt("oldpolicy", oldpolicy);
+ edit.putInt("oldring",am.getStreamVolume(AudioManager.STREAM_RING));
+ edit.putBoolean("oldvalid", true);
+ 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 float good, late, lost, loss;
+
+ /** 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();
+
+ 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();
+
+ track = new AudioTrack(AudioManager.STREAM_MUSIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ REAL_BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM);
+ 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();
+ 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);
+ }
+ timeout = 0;
+ if (running) {
+
+ //println("seq " + seq + " frame seq " + (frame.getPkt()[0]).getSeqNumber());
+ if (seq == (frame.getPkt()[0]).getSeqNumber()) {
+ m++;
+ continue;
+ }
+
+ 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");
+ 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
+ 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);
+ }
+ }
+ println("POOL SIZE " + DatagramPool.getInstance().getPoolSize());
+ track.stop();
+ //if (Receiver.pstn_state == null || Receiver.pstn_state.equals("IDLE"))
+ // am.setMode(AudioManager.MODE_NORMAL);
+ //saveVolume();
+ //am.setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0);
+ //restoreSettings();
+ ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3);
+ tg.startTone(ToneGenerator.TONE_PROP_PROMPT);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ }
+ tg.stopTone();
+ rtpSession = null;
+ track = null;
+ codec.cleanDecoder(codecCtx);
+ codec = null;
+ println("rtp receiver terminated");
+ }
+
+ /** Debug output */
+ static int i = 0;
+ private static void println(String str) {
+ System.out.println("RtpStreamReceiver "+ i++ +": " + str);
+ }
+
+ public static int byte2int(byte b) { // return (b>=0)? b : -((b^0xFF)+1);
+ // return (b>=0)? b : b+0x100;
+ return (b + 0x100) % 0x100;
+ }
+
+ 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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/RtpStreamSender.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/RtpStreamSender.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,220 @@
+/*
+ * 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 org.sipdroid.media;
+
+import java.io.InputStream;
+import java.net.DatagramPacket;
+import java.util.Random;
+
+import jlibrtp.RTPSession;
+import jlibrtp.RtpPkt;
+
+import org.sipdroid.media.codecs.Codec;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+
+/**
+ * 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;
+
+ /** The RtpSocket */
+ //private RtpSocket rtp_socket = null;
+ private RTPSession rtpSession = null;
+
+ /** Codec */
+ private Codec codec;
+
+ private int sampling_rate;
+
+ /** Number of bytes per frame */
+ private int frame_size;
+
+ private int codec_frame_size;
+
+ /**
+ * Whether it works synchronously with a local clock, or it it acts as slave
+ * of the InputStream
+ */
+ boolean do_sync = true;
+
+ int sync_adj = 0;
+
+ /** Whether it is running */
+ boolean running = false;
+ boolean muted = false;
+
+ private int codec_divider;
+
+ /**
+ * Constructs a RtpStreamSender.
+ *
+ */
+ public RtpStreamSender(Codec co, RTPSession rtpSession) {
+ init(co, rtpSession);
+ }
+
+ /** 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;
+ }
+
+ /** Sets the synchronization adjustment time (in milliseconds). */
+ public void setSyncAdj(int millisecs) {
+ sync_adj = millisecs;
+ }
+
+ /** Whether is running */
+ public boolean isRunning() {
+ return running;
+ }
+
+ public boolean mute() {
+ return muted = !muted;
+ }
+
+ public static int delay = 0;
+
+ /** Stops running */
+ public void halt() {
+ running = false;
+ }
+
+ 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;
+ if (s < sm) sm = s;
+ if (s > smin) nearend = 3000/5;
+ else if (nearend > 0) nearend--;
+ }
+ for (i = 0; i < len; i++) {
+ j = lin[i+off];
+ if (j > 6550)
+ lin[i+off] = 6550*5;
+ else if (j < -6550)
+ lin[i+off] = -6550*5;
+ else
+ lin[i+off] = (short)(j*5);
+ }
+ r = (double)len/100000;
+ smin = sm*r + smin*(1-r);
+ }
+
+ void noise(short[] lin,int off,int len,double power) {
+ int i,r = (int)(power*2);
+ short ran;
+
+ if (r == 0) r = 1;
+ for (i = 0; i < len; i += 4) {
+ ran = (short)(random.nextInt(r*2)-r);
+ lin[i+off] = ran;
+ lin[i+off+1] = ran;
+ lin[i+off+2] = ran;
+ lin[i+off+3] = ran;
+ }
+ }
+
+ public static int m;
+
+ /** Runs it in a new Thread. */
+ public void run() {
+ if (rtpSession == 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);
+ int seqn = 0;
+ long time = 0;
+ double p = 0;
+ running = true;
+ m = 1;
+
+ if (DEBUG)
+ 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,
+ AudioFormat.CHANNEL_CONFIGURATION_MONO,
+ AudioFormat.ENCODING_PCM_16BIT)*2);
+ record.startRecording();
+ short[] lin = new short[frame_size*11];
+ int num,ring = 0;
+ random = new Random();
+ 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;
+ }
+ record.stop();
+ rtpSession = null;
+ codec.cleanEncoder(codecCtx);
+ if (DEBUG)
+ println("rtp sender terminated");
+ }
+
+ /** Debug output */
+ private static void println(String str) {
+ android.util.Log.d("DEBUG","RtpStreamSender: " + str);
+ }
+}
diff -r 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/Codec.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/Codec.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,19 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/CodecInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/CodecInfo.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,43 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/CodecManager.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/CodecManager.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,46 @@
+/**
+ *
+ */
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/G711.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/G711.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,393 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/G722.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/G722.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,68 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/G722JNI.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/G722JNI.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,10 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/GSM.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/GSM.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,68 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/media/codecs/GSMJNI.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/GSMJNI.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,8 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/net/SipdroidSocket.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/SipdroidSocket.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * 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 org.sipdroid.net;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.SocketOptions;
+import java.net.UnknownHostException;
+
+import org.sipdroid.net.impl.OSNetworkSystem;
+import org.sipdroid.net.impl.PlainDatagramSocketImpl;
+
+public class SipdroidSocket extends DatagramSocket {
+
+ PlainDatagramSocketImpl impl;
+ public static boolean loaded = false;
+
+ public SipdroidSocket(int port) throws SocketException, UnknownHostException {
+ super(!loaded?port:0);
+ if (loaded) {
+ impl = new PlainDatagramSocketImpl();
+ impl.create();
+ impl.bind(port,InetAddress.getByName("0"));
+ android.util.Log.d("TEST","name : " + InetAddress.getByName("0"));
+ }
+ }
+
+ public void close() {
+ super.close();
+ if (loaded) impl.close();
+ }
+
+ public void setSoTimeout(int val) throws SocketException {
+ if (loaded) impl.setOption(SocketOptions.SO_TIMEOUT, val);
+ else super.setSoTimeout(val);
+ }
+
+ public void receive(DatagramPacket pack) throws IOException {
+ if (loaded) impl.receive(pack);
+ else super.receive(pack);
+ }
+
+ public void send(DatagramPacket pack) throws IOException {
+ if (loaded) impl.send(pack);
+ else super.send(pack);
+ }
+
+ public boolean isConnected() {
+ if (loaded) return true;
+ else return super.isConnected();
+ }
+
+ public void disconnect() {
+ if (!loaded) super.disconnect();
+ }
+
+ public void connect(InetAddress addr,int port) {
+ if (!loaded) super.connect(addr,port);
+ }
+
+ static {
+ System.loadLibrary("OSNetworkSystem");
+ OSNetworkSystem.getOSNetworkSystem().oneTimeInitialization(true);
+ SipdroidSocket.loaded = true;
+ android.util.Log.d("OSNetworkSystem", "LOADED");
+
+ }
+}
diff -r 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/net/impl/OSNetworkSystem.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/impl/OSNetworkSystem.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * 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
+ */
+
+// BEGIN android-note
+// address length was changed from long to int for performance reasons.
+// END android-note
+
+package org.sipdroid.net.impl;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.net.UnknownHostException;
+import java.nio.channels.Channel;
+// BEGIN android-removed
+// import java.nio.channels.SelectableChannel;
+// END android-removed
+/*
+ *
+ * This Class is used for native code wrap, the implement class of
+ * INetworkSystem.
+ *
+ */
+public final class OSNetworkSystem {
+
+ // ----------------------------------------------------
+ // Class Variables
+ // ----------------------------------------------------
+
+ private static final int ERRORCODE_SOCKET_TIMEOUT = -209;
+
+ private static OSNetworkSystem ref = new OSNetworkSystem();
+
+ private static final int INETADDR_REACHABLE = 0;
+
+ private static boolean isNetworkInited = false;
+
+ // ----------------------------------------------------
+ // Class Constructor
+ // ----------------------------------------------------
+
+ // can not be instantiated.
+ private OSNetworkSystem() {
+ super();
+ }
+
+ /*
+ * @return a static ref of this class
+ */
+ public static OSNetworkSystem getOSNetworkSystem() {
+ return ref;
+ }
+
+ // Useing when cache set/get is OK
+ // public static native void oneTimeInitializationDatagram(
+ // boolean jcl_IPv6_support);
+ //
+ // public static native void oneTimeInitializationSocket(
+ // boolean jcl_IPv6_support);
+
+ // --------------------------------------------------
+ // java codes that wrap native codes
+ // --------------------------------------------------
+
+ public void createSocket(FileDescriptor fd, boolean preferIPv4Stack)
+ throws IOException {
+ createSocketImpl(fd, preferIPv4Stack);
+ }
+
+ public void createDatagramSocket(FileDescriptor fd, boolean preferIPv4Stack)
+ throws SocketException {
+ createDatagramSocketImpl(fd, preferIPv4Stack);
+ }
+
+ public int read(FileDescriptor aFD, byte[] data, int offset, int count,
+ int timeout) throws IOException {
+ return readSocketImpl(aFD, data, offset, count, timeout);
+ }
+
+ public int readDirect(FileDescriptor aFD, int address, int offset, int count,
+ int timeout) throws IOException {
+ return readSocketDirectImpl(aFD, address, offset, count, timeout);
+ }
+
+ public int write(FileDescriptor aFD, byte[] data, int offset, int count)
+ throws IOException {
+ return writeSocketImpl(aFD, data, offset, count);
+ }
+
+ public int writeDirect(FileDescriptor aFD, int address, int offset,
+ int count) throws IOException {
+ return writeSocketDirectImpl(aFD, address, offset, count);
+ }
+
+ public void setNonBlocking(FileDescriptor aFD, boolean block)
+ throws IOException {
+ setNonBlockingImpl(aFD, block);
+ }
+
+ public void connectDatagram(FileDescriptor aFD, int port, int trafficClass,
+ InetAddress inetAddress) throws SocketException {
+ connectDatagramImpl2(aFD, port, trafficClass, inetAddress);
+ }
+
+ public int connect(FileDescriptor aFD, int trafficClass,
+ InetAddress inetAddress, int port) throws IOException{
+ return connectSocketImpl(aFD, trafficClass, inetAddress, port);
+ }
+
+ // BEGIN android-changed
+ public int connectWithTimeout(FileDescriptor aFD, int timeout,
+ int trafficClass, InetAddress inetAddress, int port, int step,
+ byte[] context) throws IOException{
+ return connectWithTimeoutSocketImpl(aFD, timeout, trafficClass,
+ inetAddress, port, step, context);
+ }
+ // END android-changed
+
+ public void connectStreamWithTimeoutSocket(FileDescriptor aFD, int aport,
+ int timeout, int trafficClass, InetAddress inetAddress)
+ throws IOException {
+ connectStreamWithTimeoutSocketImpl(aFD, aport, timeout, trafficClass,
+ inetAddress);
+ }
+
+ public void bind(FileDescriptor aFD, int port, InetAddress inetAddress)
+ throws SocketException {
+ socketBindImpl(aFD, port, inetAddress);
+ }
+
+ public boolean bind2(FileDescriptor aFD, int port, boolean bindToDevice,
+ InetAddress inetAddress) throws SocketException {
+ return socketBindImpl2(aFD, port, bindToDevice, inetAddress);
+ }
+
+ public void accept(FileDescriptor fdServer, SocketImpl newSocket,
+ FileDescriptor fdnewSocket, int timeout) throws IOException {
+ acceptSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
+ }
+
+ public int sendDatagram(FileDescriptor fd, byte[] data, int offset,
+ int length, int port, boolean bindToDevice, int trafficClass,
+ InetAddress inetAddress) throws IOException {
+ return sendDatagramImpl(fd, data, offset, length, port, bindToDevice,
+ trafficClass, inetAddress);
+ }
+
+ public int sendDatagramDirect(FileDescriptor fd, int address, int offset,
+ int length, int port, boolean bindToDevice, int trafficClass,
+ InetAddress inetAddress) throws IOException {
+ return sendDatagramDirectImpl(fd, address, offset, length, port, bindToDevice,
+ trafficClass, inetAddress);
+ }
+
+ public int sendDatagram2(FileDescriptor fd, byte[] data, int offset,
+ int length, int port, InetAddress inetAddress) throws IOException {
+ return sendDatagramImpl2(fd, data, offset, length, port, inetAddress);
+ }
+
+ public int receiveDatagram(FileDescriptor aFD, DatagramPacket packet,
+ byte[] data, int offset, int length, int receiveTimeout,
+ boolean peek) throws IOException {
+ return receiveDatagramImpl(aFD, packet, data, offset, length,
+ receiveTimeout, peek);
+ }
+
+ public int receiveDatagramDirect(FileDescriptor aFD, DatagramPacket packet,
+ int address, int offset, int length, int receiveTimeout,
+ boolean peek) throws IOException {
+ return receiveDatagramDirectImpl(aFD, packet, address, offset, length,
+ receiveTimeout, peek);
+ }
+
+ public int recvConnectedDatagram(FileDescriptor aFD, DatagramPacket packet,
+ byte[] data, int offset, int length, int receiveTimeout,
+ boolean peek) throws IOException {
+ return recvConnectedDatagramImpl(aFD, packet, data, offset, length,
+ receiveTimeout, peek);
+ }
+
+ public int recvConnectedDatagramDirect(FileDescriptor aFD, DatagramPacket packet, int address,
+ int offset, int length, int receiveTimeout, boolean peek)
+ throws IOException {
+ return recvConnectedDatagramDirectImpl(aFD, packet, address, offset, length, receiveTimeout, peek);
+ }
+
+ public int peekDatagram(FileDescriptor aFD, InetAddress sender,
+ int receiveTimeout) throws IOException {
+ return peekDatagramImpl(aFD, sender, receiveTimeout);
+ }
+
+ public int sendConnectedDatagram(FileDescriptor fd, byte[] data,
+ int offset, int length, boolean bindToDevice) throws IOException {
+ return sendConnectedDatagramImpl(fd, data, offset, length, bindToDevice);
+ }
+
+ public int sendConnectedDatagramDirect(FileDescriptor fd, int address,
+ int offset, int length, boolean bindToDevice) throws IOException {
+ return sendConnectedDatagramDirectImpl(fd, address, offset, length, bindToDevice);
+ }
+
+ public void disconnectDatagram(FileDescriptor aFD) throws SocketException {
+ disconnectDatagramImpl(aFD);
+ }
+
+ public void createMulticastSocket(FileDescriptor aFD,
+ boolean preferIPv4Stack) throws SocketException {
+ createMulticastSocketImpl(aFD, preferIPv4Stack);
+ }
+
+ public void createServerStreamSocket(FileDescriptor aFD,
+ boolean preferIPv4Stack) throws SocketException {
+ createServerStreamSocketImpl(aFD, preferIPv4Stack);
+ }
+
+ public int receiveStream(FileDescriptor aFD, byte[] data, int offset,
+ int count, int timeout) throws IOException {
+ return receiveStreamImpl(aFD, data, offset, count, timeout);
+ }
+
+ public int sendStream(FileDescriptor fd, byte[] data, int offset, int count)
+ throws IOException {
+ return sendStreamImpl(fd, data, offset, count);
+ }
+
+ public void shutdownInput(FileDescriptor descriptor) throws IOException {
+ shutdownInputImpl(descriptor);
+ }
+
+ public void shutdownOutput(FileDescriptor descriptor) throws IOException {
+ shutdownOutputImpl(descriptor);
+ }
+
+ public boolean supportsUrgentData(FileDescriptor fd) {
+ return supportsUrgentDataImpl(fd);
+ }
+
+ public void sendUrgentData(FileDescriptor fd, byte value) {
+ sendUrgentDataImpl(fd, value);
+ }
+
+ public int availableStream(FileDescriptor aFD) throws SocketException {
+ return availableStreamImpl(aFD);
+ }
+
+ // BEGIN android-removed
+ // public void acceptStreamSocket(FileDescriptor fdServer,
+ // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
+ // throws IOException {
+ // acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
+ // }
+ //
+ // public void createStreamSocket(FileDescriptor aFD, boolean preferIPv4Stack)
+ // throws SocketException {
+ // createStreamSocketImpl(aFD, preferIPv4Stack);
+ // }
+ // END android-removed
+
+ public void listenStreamSocket(FileDescriptor aFD, int backlog)
+ throws SocketException {
+ listenStreamSocketImpl(aFD, backlog);
+ }
+
+ // BEGIN android-removed
+ // public boolean isReachableByICMP(final InetAddress dest,
+ // InetAddress source, final int ttl, final int timeout) {
+ // return INETADDR_REACHABLE == isReachableByICMPImpl(dest, source, ttl,
+ // timeout);
+ // }
+ // END android-removed
+
+ /*
+ *
+ * @param
+ * readChannels all channels interested in read and accept
+ * @param
+ * writeChannels all channels interested in write and connect
+ * @param timeout
+ * timeout in millis @return a set of channels that are ready for operation
+ * @throws
+ * SocketException @return int array, each int approve one of the * channel if OK
+ */
+
+ public int[] select(FileDescriptor[] readFDs,
+ FileDescriptor[] writeFDs, long timeout)
+ throws SocketException {
+ int countRead = readFDs.length;
+ int countWrite = writeFDs.length;
+ int result = 0;
+ if (0 == countRead + countWrite) {
+ return (new int[0]);
+ }
+ int[] flags = new int[countRead + countWrite];
+
+ // handle timeout in native
+ result = selectImpl(readFDs, writeFDs, countRead, countWrite, flags,
+ timeout);
+
+ if (0 <= result) {
+ return flags;
+ }
+ if (ERRORCODE_SOCKET_TIMEOUT == result) {
+ return new int[0];
+ }
+ throw new SocketException();
+
+ }
+
+ public InetAddress getSocketLocalAddress(FileDescriptor aFD,
+ boolean preferIPv6Addresses) {
+ return getSocketLocalAddressImpl(aFD, preferIPv6Addresses);
+ }
+
+ /*
+ * Query the IP stack for the local port to which this socket is bound.
+ *
+ * @param aFD the socket descriptor @param preferIPv6Addresses address
+ * preference for nodes that support both IPv4 and IPv6 @return int the
+ * local port to which the socket is bound
+ */
+ public int getSocketLocalPort(FileDescriptor aFD,
+ boolean preferIPv6Addresses) {
+ return getSocketLocalPortImpl(aFD, preferIPv6Addresses);
+ }
+
+ /*
+ * Query the IP stack for the nominated socket option.
+ *
+ * @param aFD the socket descriptor @param opt the socket option type
+ * @return the nominated socket option value
+ *
+ * @throws SocketException if the option is invalid
+ */
+ public Object getSocketOption(FileDescriptor aFD, int opt)
+ throws SocketException {
+ return getSocketOptionImpl(aFD, opt);
+ }
+
+ /*
+ * Set the nominated socket option in the IP stack.
+ *
+ * @param aFD the socket descriptor @param opt the option selector @param
+ * optVal the nominated option value
+ *
+ * @throws SocketException if the option is invalid or cannot be set
+ */
+ public void setSocketOption(FileDescriptor aFD, int opt, Object optVal)
+ throws SocketException {
+ setSocketOptionImpl(aFD, opt, optVal);
+ }
+
+ public int getSocketFlags() {
+ return getSocketFlagsImpl();
+ }
+
+ /*
+ * Close the socket in the IP stack.
+ *
+ * @param aFD the socket descriptor
+ */
+ public void socketClose(FileDescriptor aFD) throws IOException {
+ socketCloseImpl(aFD);
+ }
+
+ public InetAddress getHostByAddr(byte[] addr) throws UnknownHostException {
+ return getHostByAddrImpl(addr);
+ }
+
+ public InetAddress getHostByName(String addr, boolean preferIPv6Addresses)
+ throws UnknownHostException {
+ return getHostByNameImpl(addr, preferIPv6Addresses);
+ }
+
+ public void setInetAddress(InetAddress sender, byte[] address) {
+ setInetAddressImpl(sender, address);
+ }
+
+ // ---------------------------------------------------
+ // Native Codes
+ // ---------------------------------------------------
+
+ static native void createSocketImpl(FileDescriptor fd,
+ boolean preferIPv4Stack);
+
+ /*
+ * Allocate a datagram socket in the IP stack. The socket is associated with
+ * the aFD
.
+ *
+ * @param aFD the FileDescriptor to associate with the socket @param
+ * preferIPv4Stack IP stack preference if underlying platform is V4/V6
+ * @exception SocketException upon an allocation error
+ */
+ static native void createDatagramSocketImpl(FileDescriptor aFD,
+ boolean preferIPv4Stack) throws SocketException;
+
+ static native int readSocketImpl(FileDescriptor aFD, byte[] data,
+ int offset, int count, int timeout) throws IOException;
+
+ static native int readSocketDirectImpl(FileDescriptor aFD, int address,
+ int offset, int count, int timeout) throws IOException;
+
+ static native int writeSocketImpl(FileDescriptor fd, byte[] data,
+ int offset, int count) throws IOException;
+
+ static native int writeSocketDirectImpl(FileDescriptor fd, int address,
+ int offset, int count) throws IOException;
+
+ static native void setNonBlockingImpl(FileDescriptor aFD,
+ boolean block);
+
+ static native int connectSocketImpl(FileDescriptor aFD,
+ int trafficClass, InetAddress inetAddress, int port);
+
+ // BEGIN android-changed
+ static native int connectWithTimeoutSocketImpl(
+ FileDescriptor aFD, int timeout, int trafficClass,
+ InetAddress hostname, int port, int step, byte[] context);
+ // END android-changed
+
+ static native void connectStreamWithTimeoutSocketImpl(FileDescriptor aFD,
+ int aport, int timeout, int trafficClass, InetAddress inetAddress)
+ throws IOException;
+
+ static native void socketBindImpl(FileDescriptor aFD, int port,
+ InetAddress inetAddress) throws SocketException;
+
+ static native void listenStreamSocketImpl(FileDescriptor aFD, int backlog)
+ throws SocketException;
+
+ static native int availableStreamImpl(FileDescriptor aFD)
+ throws SocketException;
+
+ static native void acceptSocketImpl(FileDescriptor fdServer,
+ SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
+ throws IOException;
+
+ static native boolean supportsUrgentDataImpl(FileDescriptor fd);
+
+ static native void sendUrgentDataImpl(FileDescriptor fd, byte value);
+
+ /*
+ * Connect the socket to a port and address
+ *
+ * @param aFD the FileDescriptor to associate with the socket @param port
+ * the port to connect to @param trafficClass the traffic Class to be used
+ * then the connection is made @param inetAddress address to connect to.
+ *
+ * @exception SocketException if the connect fails
+ */
+ static native void connectDatagramImpl2(FileDescriptor aFD,
+ int port, int trafficClass, InetAddress inetAddress)
+ throws SocketException;
+
+ /*
+ * Disconnect the socket to a port and address
+ *
+ * @param aFD the FileDescriptor to associate with the socket
+ *
+ * @exception SocketException if the disconnect fails
+ */
+ static native void disconnectDatagramImpl(FileDescriptor aFD)
+ throws SocketException;
+
+ /*
+ * Allocate a datagram socket in the IP stack. The socket is associated with
+ * the aFD
.
+ *
+ * @param aFD the FileDescriptor to associate with the socket @param
+ * preferIPv4Stack IP stack preference if underlying platform is V4/V6
+ * @exception SocketException upon an allocation error
+ */
+
+ /*
+ * Bind the socket to the port/localhost in the IP stack.
+ *
+ * @param aFD the socket descriptor @param port the option selector @param
+ * bindToDevice bind the socket to the specified interface @param
+ * inetAddress address to connect to. @return if bind successful @exception
+ * SocketException thrown if bind operation fails
+ */
+ static native boolean socketBindImpl2(FileDescriptor aFD,
+ int port, boolean bindToDevice, InetAddress inetAddress)
+ throws SocketException;
+
+ /*
+ * Peek on the socket, update sender
address and answer the
+ * sender port.
+ *
+ * @param aFD the socket FileDescriptor @param sender an InetAddress, to be
+ * updated with the sender's address @param receiveTimeout the maximum
+ * length of time the socket should block, reading @return int the sender
+ * port
+ *
+ * @exception IOException upon an read error or timeout
+ */
+ static native int peekDatagramImpl(FileDescriptor aFD,
+ InetAddress sender, int receiveTimeout) throws IOException;
+
+ /*
+ * Recieve data on the socket into the specified buffer. The packet fields
+ * data
& length
are passed in addition to
+ * packet
to eliminate the JNI field access calls.
+ *
+ * @param aFD the socket FileDescriptor @param packet the DatagramPacket to
+ * receive into @param data the data buffer of the packet @param offset the
+ * offset in the data buffer @param length the length of the data buffer in
+ * the packet @param receiveTimeout the maximum length of time the socket
+ * should block, reading @param peek indicates to peek at the data @return
+ * number of data received @exception IOException upon an read error or
+ * timeout
+ */
+ static native int receiveDatagramImpl(FileDescriptor aFD,
+ DatagramPacket packet, byte[] data, int offset, int length,
+ int receiveTimeout, boolean peek) throws IOException;
+
+ static native int receiveDatagramDirectImpl(FileDescriptor aFD,
+ DatagramPacket packet, int address, int offset, int length,
+ int receiveTimeout, boolean peek) throws IOException;
+
+ /*
+ * Recieve data on the connected socket into the specified buffer. The
+ * packet fields data
& length
are passed in
+ * addition to packet
to eliminate the JNI field access
+ * calls.
+ *
+ * @param aFD the socket FileDescriptor @param packet the DatagramPacket to
+ * receive into @param data the data buffer of the packet @param offset the
+ * offset in the data buffer @param length the length of the data buffer in
+ * the packet @param receiveTimeout the maximum length of time the socket
+ * should block, reading @param peek indicates to peek at the data @return
+ * number of data received @exception IOException upon an read error or
+ * timeout
+ */
+ static native int recvConnectedDatagramImpl(FileDescriptor aFD,
+ DatagramPacket packet, byte[] data, int offset, int length,
+ int receiveTimeout, boolean peek) throws IOException;
+
+ static native int recvConnectedDatagramDirectImpl(FileDescriptor aFD,
+ DatagramPacket packet, int address, int offset, int length,
+ int receiveTimeout, boolean peek) throws IOException;
+
+ /*
+ * Send the data
to the nominated target address
+ * and port
. These values are derived from the
+ * DatagramPacket to reduce the field calls within JNI.
+ *
+ * @param fd the socket FileDescriptor @param data the data buffer of the
+ * packet @param offset the offset in the data buffer @param length the
+ * length of the data buffer in the packet @param port the target host port
+ * @param bindToDevice if bind to device @param trafficClass the traffic
+ * class to be used when the datagram is sent @param inetAddress address to
+ * connect to. @return number of data send
+ *
+ * @exception IOException upon an read error or timeout
+ */
+ static native int sendDatagramImpl(FileDescriptor fd,
+ byte[] data, int offset, int length, int port,
+ boolean bindToDevice, int trafficClass, InetAddress inetAddress)
+ throws IOException;
+
+ static native int sendDatagramDirectImpl(FileDescriptor fd,
+ int address, int offset, int length, int port,
+ boolean bindToDevice, int trafficClass, InetAddress inetAddress)
+ throws IOException;
+
+ /*
+ * Send the data
to the address and port to which the was
+ * connnected and port
.
+ *
+ * @param fd the socket FileDescriptor @param data the data buffer of the
+ * packet @param offset the offset in the data buffer @param length the
+ * length of the data buffer in the packet @param bindToDevice not used,
+ * current kept in case needed as was the case for sendDatagramImpl @return
+ * number of data send @exception IOException upon an read error or timeout
+ */
+ static native int sendConnectedDatagramImpl(FileDescriptor fd,
+ byte[] data, int offset, int length, boolean bindToDevice)
+ throws IOException;
+
+ static native int sendConnectedDatagramDirectImpl(FileDescriptor fd,
+ int address, int offset, int length, boolean bindToDevice)
+ throws IOException;
+
+ /*
+ * Answer the result of attempting to create a server stream socket in the
+ * IP stack. Any special options required for server sockets will be set by
+ * this method.
+ *
+ * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4
+ * @exception SocketException if an error occurs while creating the socket
+ */
+ static native void createServerStreamSocketImpl(FileDescriptor aFD,
+ boolean preferIPv4Stack) throws SocketException;
+
+ /*
+ * Answer the result of attempting to create a multicast socket in the IP
+ * stack. Any special options required for server sockets will be set by
+ * this method.
+ *
+ * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4
+ * @exception SocketException if an error occurs while creating the socket
+ */
+ static native void createMulticastSocketImpl(FileDescriptor aFD,
+ boolean preferIPv4Stack) throws SocketException;
+
+ /*
+ * Recieve at most count
bytes into the buffer data
+ * at the offset
on the socket.
+ *
+ * @param aFD the socket FileDescriptor @param data the receive buffer
+ * @param offset the offset into the buffer @param count the max number of
+ * bytes to receive @param timeout the max time the read operation should
+ * block waiting for data @return int the actual number of bytes read
+ * @throws IOException @exception SocketException if an error occurs while
+ * reading
+ */
+ static native int receiveStreamImpl(FileDescriptor aFD, byte[] data,
+ int offset, int count, int timeout) throws IOException;
+
+ /*
+ * Send count
bytes from the buffer data
at
+ * the offset
, on the socket.
+ *
+ * @param fd
+ *
+ * @param data the send buffer @param offset the offset into the buffer
+ * @param count the number of bytes to receive @return int the actual number
+ * of bytes sent @throws IOException @exception SocketException if an error
+ * occurs while writing
+ */
+ static native int sendStreamImpl(FileDescriptor fd, byte[] data,
+ int offset, int count) throws IOException;
+
+ private native void shutdownInputImpl(FileDescriptor descriptor)
+ throws IOException;
+
+ private native void shutdownOutputImpl(FileDescriptor descriptor)
+ throws IOException;
+
+ // BEGIN android-removed
+ // static native void acceptStreamSocketImpl(FileDescriptor fdServer,
+ // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
+ // throws IOException;
+ //
+ // static native void createStreamSocketImpl(FileDescriptor aFD,
+ // boolean preferIPv4Stack) throws SocketException;
+ // END android-removed
+
+ static native int sendDatagramImpl2(FileDescriptor fd, byte[] data,
+ int offset, int length, int port, InetAddress inetAddress)
+ throws IOException;
+
+ static native int selectImpl(FileDescriptor[] readfd,
+ FileDescriptor[] writefd, int cread, int cwirte, int[] flags,
+ long timeout);
+
+ static native InetAddress getSocketLocalAddressImpl(FileDescriptor aFD,
+ boolean preferIPv6Addresses);
+
+ /*
+ * Query the IP stack for the local port to which this socket is bound.
+ *
+ * @param aFD the socket descriptor @param preferIPv6Addresses address
+ * preference for nodes that support both IPv4 and IPv6 @return int the
+ * local port to which the socket is bound
+ */
+ static native int getSocketLocalPortImpl(FileDescriptor aFD,
+ boolean preferIPv6Addresses);
+
+ /*
+ * Query the IP stack for the nominated socket option.
+ *
+ * @param aFD the socket descriptor @param opt the socket option type
+ * @return the nominated socket option value
+ *
+ * @throws SocketException if the option is invalid
+ */
+ static native Object getSocketOptionImpl(FileDescriptor aFD, int opt)
+ throws SocketException;
+
+ /*
+ * Set the nominated socket option in the IP stack.
+ *
+ * @param aFD the socket descriptor @param opt the option selector @param
+ * optVal the nominated option value
+ *
+ * @throws SocketException if the option is invalid or cannot be set
+ */
+ static native void setSocketOptionImpl(FileDescriptor aFD, int opt,
+ Object optVal) throws SocketException;
+
+ static native int getSocketFlagsImpl();
+
+ /*
+ * Close the socket in the IP stack.
+ *
+ * @param aFD the socket descriptor
+ */
+ static native void socketCloseImpl(FileDescriptor aFD);
+
+ static native InetAddress getHostByAddrImpl(byte[] addr)
+ throws UnknownHostException;
+
+ static native InetAddress getHostByNameImpl(String addr,
+ boolean preferIPv6Addresses) throws UnknownHostException;
+
+ native void setInetAddressImpl(InetAddress sender, byte[] address);
+
+ // BEGIN android-removed
+ // native int isReachableByICMPImpl(InetAddress addr, InetAddress local,
+ // int ttl, int timeout);
+ // END android-removed
+
+ native Channel inheritedChannelImpl();
+
+ public Channel inheritedChannel() {
+ return inheritedChannelImpl();
+ }
+
+ public void oneTimeInitialization(boolean jcl_supports_ipv6){
+ if (!isNetworkInited){
+ oneTimeInitializationImpl(jcl_supports_ipv6);
+ isNetworkInited = true;
+ }
+ }
+
+ native void oneTimeInitializationImpl (boolean jcl_supports_ipv6);
+}
\ No newline at end of file
diff -r 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ *
+ * 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 org.sipdroid.net.impl;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocketImpl;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOptions;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+import java.security.AccessController;
+
+/**
+ * The default, concrete instance of datagram sockets. This class does not
+ * support security checks. Alternative types of DatagramSocketImpl's may be
+ * used by setting the impl.prefix
system property.
+ */
+public class PlainDatagramSocketImpl extends DatagramSocketImpl {
+
+ static final int MULTICAST_IF = 1;
+
+ static final int MULTICAST_TTL = 2;
+
+ static final int TCP_NODELAY = 4;
+
+ static final int FLAG_SHUTDOWN = 8;
+
+ private final static int SO_BROADCAST = 32;
+
+ final static int IP_MULTICAST_ADD = 19;
+
+ final static int IP_MULTICAST_DROP = 20;
+
+ final static int IP_MULTICAST_TTL = 17;
+
+ /**
+ * for datagram and multicast sockets we have to set REUSEADDR and REUSEPORT
+ * when REUSEADDR is set for other types of sockets we need to just set
+ * REUSEADDR therefore we have this other option which sets both if
+ * supported by the platform. this cannot be in SOCKET_OPTIONS because since
+ * it is a public interface it ends up being public even if it is not
+ * declared public
+ */
+ static final int REUSEADDR_AND_REUSEPORT = 10001;
+
+ private boolean bindToDevice;
+
+ private byte[] ipaddress = { 0, 0, 0, 0 };
+
+ private int ttl = 1;
+
+ private OSNetworkSystem netImpl = OSNetworkSystem.getOSNetworkSystem();
+
+ private volatile boolean isNativeConnected = false;
+
+ public int receiveTimeout;
+
+ public boolean streaming = true;
+
+ public boolean shutdownInput;
+
+ /**
+ * used to keep address to which the socket was connected to at the native
+ * level
+ */
+ private InetAddress connectedAddress;
+
+ private int connectedPort = -1;
+
+ /**
+ * used to store the trafficClass value which is simply returned as the
+ * value that was set. We also need it to pass it to methods that specify an
+ * address packets are going to be sent to
+ */
+ private int trafficClass;
+
+ public PlainDatagramSocketImpl(FileDescriptor fd, int localPort) {
+ super();
+ this.fd = fd;
+ this.localPort = localPort;
+ }
+
+ public PlainDatagramSocketImpl() {
+ super();
+ fd = new FileDescriptor();
+ }
+
+ @Override
+ public void bind(int port, InetAddress addr) throws SocketException {
+ String prop = null; //AccessController.doPrivileged(new PriviAction("bindToDevice")); //$NON-NLS-1$
+ boolean useBindToDevice = prop != null && prop.toLowerCase().equals("true"); //$NON-NLS-1$
+ bindToDevice = netImpl.bind2(fd, port, useBindToDevice, addr);
+ if (0 != port) {
+ localPort = port;
+ } else {
+// localPort = netImpl.getSocketLocalPort(fd, NetUtil.preferIPv6Addresses());
+ }
+
+ try {
+ // Ignore failures
+ setOption(SO_BROADCAST, Boolean.TRUE);
+ } catch (IOException e) {
+ }
+ }
+
+ @Override
+ public void close() {
+ synchronized (fd) {
+ if (fd.valid()) {
+ try {
+ netImpl.socketClose(fd);
+ } catch (IOException e) {
+ }
+ fd = new FileDescriptor();
+ }
+ }
+ }
+
+ @Override
+ public void create() throws SocketException {
+ netImpl.createDatagramSocket(fd, false); //NetUtil.preferIPv4Stack());
+ }
+
+ @Override
+ protected void finalize() {
+ close();
+ }
+
+ @Override
+ public Object getOption(int optID) throws SocketException {
+ if (optID == SocketOptions.SO_TIMEOUT) {
+ return Integer.valueOf(receiveTimeout);
+ } else if (optID == SocketOptions.IP_TOS) {
+ return Integer.valueOf(trafficClass);
+ } else {
+ // Call the native first so there will be
+ // an exception if the socket if closed.
+ Object result = netImpl.getSocketOption(fd, optID);
+ if (optID == SocketOptions.IP_MULTICAST_IF
+ && (netImpl.getSocketFlags() & MULTICAST_IF) != 0) {
+ try {
+ return InetAddress.getByAddress(ipaddress);
+ } catch (UnknownHostException e) {
+ return null;
+ }
+ }
+ return result;
+ }
+ }
+
+ @Override
+ public int getTimeToLive() throws IOException {
+ // Call the native first so there will be an exception if the socket if
+ // closed.
+ int result = (((Byte) getOption(IP_MULTICAST_TTL)).byteValue()) & 0xFF;
+ if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+ return ttl;
+ }
+ return result;
+ }
+
+ @Override
+ public byte getTTL() throws IOException {
+ // Call the native first so there will be an exception if the socket if
+ // closed.
+ byte result = ((Byte) getOption(IP_MULTICAST_TTL)).byteValue();
+ if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+ return (byte) ttl;
+ }
+ return result;
+ }
+
+ @Override
+ public void join(InetAddress addr) throws IOException {
+// setOption(IP_MULTICAST_ADD, new GenericIPMreq(addr));
+ }
+
+ @Override
+ public void joinGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException {
+ if (addr instanceof InetSocketAddress) {
+ InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
+// setOption(IP_MULTICAST_ADD, new GenericIPMreq(groupAddr, netInterface));
+ }
+ }
+
+ @Override
+ public void leave(InetAddress addr) throws IOException {
+// setOption(IP_MULTICAST_DROP, new GenericIPMreq(addr));
+ }
+
+ @Override
+ public void leaveGroup(SocketAddress addr, NetworkInterface netInterface)
+ throws IOException {
+ if (addr instanceof InetSocketAddress) {
+ InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
+// setOption(IP_MULTICAST_DROP, new GenericIPMreq(groupAddr, netInterface));
+ }
+ }
+
+ @Override
+ protected int peek(InetAddress sender) throws IOException {
+ if (isNativeConnected) {
+ /*
+ * in this case we know the port and address from which the data
+ * must have be been received as the socket is connected. However,
+ * we still need to do the receive in order to know that there was
+ * data received. We use a short buffer as we don't actually need
+ * the packet, only the knowledge that it is there
+ */
+ byte[] storageArray = new byte[10];
+ DatagramPacket pack = new DatagramPacket(storageArray, storageArray.length);
+ netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+ .getLength(), receiveTimeout, true); // peek
+ // to set the sender ,we now use a native function
+ // sender.ipaddress = connectedAddress.getAddress();
+ netImpl.setInetAddress(sender, connectedAddress.getAddress());
+ return connectedPort;
+ }
+ return netImpl.peekDatagram(fd, sender, receiveTimeout);
+ }
+
+ @Override
+ public void receive(DatagramPacket pack) throws java.io.IOException {
+ try {
+ if (isNativeConnected) {
+ // do not peek
+ netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+ .getLength(), receiveTimeout, false);
+ updatePacketRecvAddress(pack);
+ } else {
+ // receiveDatagramImpl2
+ netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+ .getLength(), receiveTimeout, false);
+ }
+ } catch (InterruptedIOException e) {
+ throw new SocketTimeoutException(e.getMessage());
+ }
+ }
+
+ @Override
+ public void send(DatagramPacket packet) throws IOException {
+
+ if (isNativeConnected) {
+ netImpl.sendConnectedDatagram(fd, packet.getData(), packet.getOffset(), packet
+ .getLength(), bindToDevice);
+ } else {
+ // sendDatagramImpl2
+ netImpl.sendDatagram(fd, packet.getData(), packet.getOffset(), packet.getLength(),
+ packet.getPort(), bindToDevice, trafficClass, packet.getAddress());
+ }
+ }
+
+ /**
+ * Set the nominated socket option. As the timeouts are not set as options
+ * in the IP stack, the value is stored in an instance field.
+ *
+ * @throws SocketException thrown if the option value is unsupported or
+ * invalid
+ */
+ @Override
+ public void setOption(int optID, Object val) throws SocketException {
+ /*
+ * for datagram sockets on some platforms we have to set both the
+ * REUSEADDR AND REUSEPORT so for REUSEADDR set this option option which
+ * tells the VM to set the two values as appropriate for the platform
+ */
+ if (optID == SocketOptions.SO_REUSEADDR) {
+ optID = REUSEADDR_AND_REUSEPORT;
+ }
+
+ if (optID == SocketOptions.SO_TIMEOUT) {
+ receiveTimeout = ((Integer) val).intValue();
+ } else {
+ int flags = netImpl.getSocketFlags();
+ try {
+ netImpl.setSocketOption(fd, optID | (flags << 16), val);
+ } catch (SocketException e) {
+ // we don't throw an exception for IP_TOS even if the platform
+ // won't let us set the requested value
+ if (optID != SocketOptions.IP_TOS) {
+ throw e;
+ }
+ }
+ if (optID == SocketOptions.IP_MULTICAST_IF && (flags & MULTICAST_IF) != 0) {
+ InetAddress inet = (InetAddress) val;
+// if (NetUtil.bytesToInt(inet.getAddress(), 0) == 0 || inet.isLoopbackAddress()) {
+// ipaddress = ((InetAddress) val).getAddress();
+// } else
+ {
+ InetAddress local = null;
+ try {
+ local = InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ throw new SocketException("getLocalHost(): " + e.toString());
+ }
+ if (inet.equals(local)) {
+ ipaddress = ((InetAddress) val).getAddress();
+ } else {
+ throw new SocketException(val + " != getLocalHost(): " + local);
+ }
+ }
+ }
+ /*
+ * save this value as it is actually used differently for IPv4 and
+ * IPv6 so we cannot get the value using the getOption. The option
+ * is actually only set for IPv4 and a masked version of the value
+ * will be set as only a subset of the values are allowed on the
+ * socket. Therefore we need to retain it to return the value that
+ * was set. We also need the value to be passed into a number of
+ * natives so that it can be used properly with IPv6
+ */
+ if (optID == SocketOptions.IP_TOS) {
+ trafficClass = ((Integer) val).intValue();
+ }
+ }
+ }
+
+ @Override
+ public void setTimeToLive(int ttl) throws java.io.IOException {
+ setOption(IP_MULTICAST_TTL, Byte.valueOf((byte) (ttl & 0xFF)));
+ if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+ this.ttl = ttl;
+ }
+ }
+
+ @Override
+ public void setTTL(byte ttl) throws java.io.IOException {
+ setOption(IP_MULTICAST_TTL, Byte.valueOf(ttl));
+ if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+ this.ttl = ttl;
+ }
+ }
+
+ @Override
+ public void connect(InetAddress inetAddr, int port) throws SocketException {
+
+ // connectDatagram impl2
+ netImpl.connectDatagram(fd, port, trafficClass, inetAddr);
+
+ // if we get here then we are connected at the native level
+ try {
+ connectedAddress = InetAddress.getByAddress(inetAddr.getAddress());
+ } catch (UnknownHostException e) {
+ // this is never expected to happen as we should not have gotten
+ // here if the address is not resolvable
+ throw new SocketException("K0317 "+inetAddr.getHostName()); //$NON-NLS-1$
+ }
+ connectedPort = port;
+ isNativeConnected = true;
+ }
+
+ @Override
+ public void disconnect() {
+ try {
+ netImpl.disconnectDatagram(fd);
+ } catch (Exception e) {
+ // there is currently no way to return an error so just eat any
+ // exception
+ }
+ connectedPort = -1;
+ connectedAddress = null;
+ isNativeConnected = false;
+ }
+
+ @Override
+ public int peekData(DatagramPacket pack) throws IOException {
+ try {
+ if (isNativeConnected) {
+ netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+ .getLength(), receiveTimeout, true); // peek
+ updatePacketRecvAddress(pack);
+ } else {
+ // receiveDatagram 2
+ netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+ .getLength(), receiveTimeout, true); // peek
+ }
+ } catch (InterruptedIOException e) {
+ throw new SocketTimeoutException(e.toString());
+ }
+ return pack.getPort();
+ }
+
+ /**
+ * Set the received address and port in the packet. We do this when the
+ * Datagram socket is connected at the native level and the
+ * recvConnnectedDatagramImpl does not update the packet with address from
+ * which the packet was received
+ *
+ * @param packet
+ * the packet to be updated
+ */
+ private void updatePacketRecvAddress(DatagramPacket packet) {
+ packet.setAddress(connectedAddress);
+ packet.setPort(connectedPort);
+ }
+
+}
\ No newline at end of file
diff -r 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/net/tools/DataFramePool.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/DataFramePool.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,44 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/net/tools/DatagramPool.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/DatagramPool.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,45 @@
+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 047b5e2b9904 -r af3a788344f9 src/org/sipdroid/net/tools/GenericPool.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/GenericPool.java Thu Jan 21 01:35:17 2010 +0100
@@ -0,0 +1,31 @@
+package org.sipdroid.net.tools;
+
+public class GenericPool extends ObjectPool