src/jlibrtp/RTPSession.java
changeset 823 2036ebfaccda
child 826 8649e502be0e
equal deleted inserted replaced
536:537ddd8aa407 823:2036ebfaccda
       
     1 /**
       
     2  * Java RTP Library (jlibrtp)
       
     3  * Copyright (C) 2006 Arne Kepp
       
     4  * 
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2.1 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  * 
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this library; if not, write to the Free Software
       
    17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
       
    18  */
       
    19 package jlibrtp;
       
    20 
       
    21 import java.net.DatagramPacket;
       
    22 import java.net.DatagramSocket;
       
    23 import java.net.InetAddress;
       
    24 import java.net.InetSocketAddress;
       
    25 import java.net.MulticastSocket;
       
    26 import java.util.Enumeration;
       
    27 import java.util.Iterator;
       
    28 import java.util.Random;
       
    29 import java.util.concurrent.locks.Condition;
       
    30 import java.util.concurrent.locks.Lock;
       
    31 import java.util.concurrent.locks.ReentrantLock;
       
    32 
       
    33 import org.sipdroid.net.tools.DataFramePool;
       
    34 import org.sipdroid.net.tools.DatagramPool;
       
    35 import org.sipdroid.net.tools.PktBufNodePool;
       
    36 import org.sipdroid.net.tools.RtpPktPool;
       
    37 
       
    38 import android.util.Log;
       
    39 
       
    40 /**
       
    41  * The RTPSession object is the core of jlibrtp.
       
    42  * 
       
    43  * One should be instantiated for every communication channel, i.e. if you send
       
    44  * voice and video, you should create one for each.
       
    45  * 
       
    46  * The instance holds a participant database, as well as other information about
       
    47  * the session. When the application registers with the session, the necessary
       
    48  * threads for receiving and processing RTP packets are spawned.
       
    49  * 
       
    50  * RTP Packets are sent synchronously, all other operations are asynchronous.
       
    51  * 
       
    52  * @author Arne Kepp
       
    53  */
       
    54 public class RTPSession {
       
    55 	/**
       
    56 	 * The debug level is final to avoid compilation of if-statements.</br> 0
       
    57 	 * provides no debugging information, 20 provides everything </br> Debug
       
    58 	 * output is written to System.out</br> Debug level for RTP related things.
       
    59 	 */
       
    60 	final static public int rtpDebugLevel = 1;
       
    61 	/**
       
    62 	 * The debug level is final to avoid compilation of if-statements.</br> 0
       
    63 	 * provides no debugging information, 20 provides everything </br> Debug
       
    64 	 * output is written to System.out</br> Debug level for RTCP related things.
       
    65 	 */
       
    66 	final static public int rtcpDebugLevel = 1;
       
    67 
       
    68 	/** RTP unicast socket */
       
    69 	protected DatagramSocket rtpSock = null;
       
    70 	/** RTP multicast socket */
       
    71 	protected MulticastSocket rtpMCSock = null;
       
    72 	/** RTP multicast group */
       
    73 	protected InetAddress mcGroup = null;
       
    74 
       
    75 	// Internal state
       
    76 	/** Whether this session is a multicast session or not */
       
    77 	protected boolean mcSession = false;
       
    78 	/** Current payload type, can be changed by application */
       
    79 	protected int payloadType = 0;
       
    80 	/** SSRC of this session */
       
    81 	protected long ssrc;
       
    82 	/** The last timestamp when we sent something */
       
    83 	protected long lastTimestamp = 0;
       
    84 	/** Current sequence number */
       
    85 	protected int seqNum = 0;
       
    86 	/** Number of packets sent by this session */
       
    87 	protected int sentPktCount = 0;
       
    88 	/** Number of octets sent by this session */
       
    89 	protected int sentOctetCount = 0;
       
    90 
       
    91 	/** The random seed */
       
    92 	protected Random random = null;
       
    93 
       
    94 	/** Session bandwidth in BYTES per second */
       
    95 	protected int bandwidth = 8000;
       
    96 
       
    97 	/** By default we do not return packets from strangers in unicast mode */
       
    98 	protected boolean naiveReception = false;
       
    99 
       
   100 	/** Should the library attempt frame reconstruction? */
       
   101 	protected boolean frameReconstruction = true;
       
   102 
       
   103 	/** Maximum number of packets used for reordering */
       
   104 	protected int pktBufBehavior = 3;
       
   105 
       
   106 	/** Participant database */
       
   107 	protected ParticipantDatabase partDb = new ParticipantDatabase(this);
       
   108 	/** First participant */
       
   109 	protected Participant firstPart;
       
   110 	/** Handle to application interface for RTP */
       
   111 	protected RTPAppIntf appIntf = null;
       
   112 	/** Handle to application interface for RTCP (optional) */
       
   113 	protected RTCPAppIntf rtcpAppIntf = null;
       
   114 	/** Handle to application interface for AVPF, RFC 4585 (optional) */
       
   115 	protected RTCPAVPFIntf rtcpAVPFIntf = null;
       
   116 	/** Handle to application interface for debugging */
       
   117 	protected DebugAppIntf debugAppIntf = null;
       
   118 
       
   119 	/** The RTCP session associated with this RTP Session */
       
   120 	protected RTCPSession rtcpSession = null;
       
   121 	/** The thread for receiving RTP packets */
       
   122 	protected RTPReceiverThread recvThrd = null;
       
   123 	/** The thread for invoking callbacks for RTP packets */
       
   124 	protected AppCallerThread appCallerThrd = null;
       
   125 
       
   126 	/** Lock to protect the packet buffers */
       
   127 	final protected Lock pktBufLock = new ReentrantLock();
       
   128 	/** Condition variable, to tell the */
       
   129 	final protected Condition pktBufDataReady = pktBufLock.newCondition();
       
   130 
       
   131 	/** Enough is enough, set to true when you want to quit. */
       
   132 	protected boolean endSession = false;
       
   133 	/** Only one registered application, please */
       
   134 	protected boolean registered = false;
       
   135 	/** We're busy resolving a SSRC conflict, please try again later */
       
   136 	protected boolean conflict = false;
       
   137 	/** Number of conflicts observed, exessive number suggests loop in network */
       
   138 	protected int conflictCount = 0;
       
   139 
       
   140 	/** SDES CNAME */
       
   141 	protected String cname = null;
       
   142 	/** SDES The participant's real name */
       
   143 	public String name = null;
       
   144 	/** SDES The participant's email */
       
   145 	public String email = null;
       
   146 	/** SDES The participant's phone number */
       
   147 	public String phone = null;
       
   148 	/** SDES The participant's location */
       
   149 	public String loc = null;
       
   150 	/** SDES The tool the participants is using */
       
   151 	public String tool = null;
       
   152 	/** SDES A note */
       
   153 	public String note = null;
       
   154 	/** SDES A priv string, loosely defined */
       
   155 	public String priv = null;
       
   156 
       
   157 	// RFC 4585 stuff. This should live on RTCPSession, but we need to have this
       
   158 	// infromation ready by the time the RTCP Session starts
       
   159 	// 0 = RFC 3550 , -1 = ACK , 1 = Immediate feedback, 2 = Early RTCP,
       
   160 	protected int rtcpMode = 0;
       
   161 	protected int fbEarlyThreshold = -1; // group size, immediate -> early
       
   162 	// transition point
       
   163 	protected int fbRegularThreshold = -1; // group size, early -> regular
       
   164 	// transition point
       
   165 	protected int minInterval = 5000; // minimum interval
       
   166 	protected int fbMaxDelay = 1000; // how long the information is useful
       
   167 	// RTCP bandwidth
       
   168 	protected int rtcpBandwidth = -1;
       
   169 
       
   170 	/**
       
   171 	 * Returns an instance of a <b>unicast</b> RTP session. Following this you
       
   172 	 * should adjust any settings and then register your application.
       
   173 	 * 
       
   174 	 * The sockets should have external ip addresses, else your CNAME
       
   175 	 * automatically generated CNAMe will be bad.
       
   176 	 * 
       
   177 	 * @param rtpSocket
       
   178 	 *            UDP socket to receive RTP communication on
       
   179 	 * @param rtcpSocket
       
   180 	 *            UDP socket to receive RTCP communication on, null if none.
       
   181 	 */
       
   182 	public RTPSession(DatagramSocket rtpSocket, DatagramSocket rtcpSocket) {
       
   183 		mcSession = false;
       
   184 		rtpSock = rtpSocket;
       
   185 		this.generateCNAME();
       
   186 		this.generateSsrc();
       
   187 		this.rtcpSession = new RTCPSession(this, rtcpSocket);
       
   188 		// The sockets are not always imediately available?
       
   189 		try {
       
   190 			Thread.sleep(1);
       
   191 		} catch (InterruptedException e) {
       
   192 			System.out.println("RTPSession sleep failed");
       
   193 		}
       
   194 	}
       
   195 
       
   196 	/**
       
   197 	 * Returns an instance of a <b>multicast</b> RTP session. Following this you
       
   198 	 * should register your application.
       
   199 	 * 
       
   200 	 * The sockets should have external ip addresses, else your CNAME
       
   201 	 * automatically generated CNAMe will be bad.
       
   202 	 * 
       
   203 	 * @param rtpSock
       
   204 	 *            a multicast socket to receive RTP communication on
       
   205 	 * @param rtcpSock
       
   206 	 *            a multicast socket to receive RTP communication on
       
   207 	 * @param multicastGroup
       
   208 	 *            the multicast group that we want to communicate with.
       
   209 	 */
       
   210 	public RTPSession(MulticastSocket rtpSock, MulticastSocket rtcpSock,
       
   211 			InetAddress multicastGroup) throws Exception {
       
   212 		mcSession = true;
       
   213 		rtpMCSock = rtpSock;
       
   214 		mcGroup = multicastGroup;
       
   215 		rtpMCSock.joinGroup(mcGroup);
       
   216 		rtcpSock.joinGroup(mcGroup);
       
   217 		this.generateCNAME();
       
   218 		this.generateSsrc();
       
   219 		this.rtcpSession = new RTCPSession(this, rtcpSock, mcGroup);
       
   220 
       
   221 		// The sockets are not always imediately available?
       
   222 		try {
       
   223 			Thread.sleep(1);
       
   224 		} catch (InterruptedException e) {
       
   225 			System.out.println("RTPSession sleep failed");
       
   226 		}
       
   227 	}
       
   228 
       
   229 	/**
       
   230 	 * Registers an application (RTPAppIntf) with the RTP session. The session
       
   231 	 * will call receiveData() on the supplied instance whenever data has been
       
   232 	 * received.
       
   233 	 * 
       
   234 	 * Following this you should set the payload type and add participants to
       
   235 	 * the session.
       
   236 	 * 
       
   237 	 * @param rtpApp
       
   238 	 *            an object that implements the RTPAppIntf-interface
       
   239 	 * @param rtcpApp
       
   240 	 *            an object that implements the RTCPAppIntf-interface (optional)
       
   241 	 * @return -1 if this RTPSession-instance already has an application
       
   242 	 *         registered.
       
   243 	 */
       
   244 	public int RTPSessionRegister(RTPAppIntf rtpApp, RTCPAppIntf rtcpApp,
       
   245 			DebugAppIntf debugApp) {
       
   246 		if (registered) {
       
   247 			System.out
       
   248 			.println("RTPSessionRegister(): Can\'t register another application!");
       
   249 			return -1;
       
   250 		} else {
       
   251 
       
   252 			registered = true;
       
   253 			generateSeqNum();
       
   254 			if (RTPSession.rtpDebugLevel > 0) {
       
   255 				System.out.println("-> RTPSessionRegister");
       
   256 			}
       
   257 			this.appIntf = rtpApp;
       
   258 			this.rtcpAppIntf = rtcpApp;
       
   259 			this.debugAppIntf = debugApp;
       
   260 
       
   261 			recvThrd = new RTPReceiverThread(this);
       
   262 			appCallerThrd = new AppCallerThread(this, rtpApp);
       
   263 			//recvThrd.start();
       
   264 			//appCallerThrd.start();
       
   265 			//rtcpSession.start();
       
   266 			return 0;
       
   267 		}
       
   268 	}
       
   269 
       
   270 	public AppCallerThread getAppCallerThrd() {
       
   271 		return appCallerThrd;
       
   272 	}
       
   273 
       
   274 	public RTPReceiverThread getRTPRecvThrd() {
       
   275 		return recvThrd;
       
   276 	}
       
   277 
       
   278 	/**
       
   279 	 * Send data to all participants registered as receivers, using the current
       
   280 	 * timeStamp, dynamic sequence number and the current payload type specified
       
   281 	 * for the session.
       
   282 	 * 
       
   283 	 * @param buf
       
   284 	 *            A buffer of bytes, less than 1496 bytes
       
   285 	 * @return null if there was a problem, {RTP Timestamp, Sequence number}
       
   286 	 *         otherwise
       
   287 	 */
       
   288 	public long[] sendData(byte[] buf) {
       
   289 		byte[][] tmp = { buf };
       
   290 		long[][] ret = this.sendData(tmp, null, null, -1, null);
       
   291 
       
   292 		if (ret != null)
       
   293 			return ret[0];
       
   294 
       
   295 		return null;
       
   296 	}
       
   297 
       
   298 	/**
       
   299 	 * Send data to all participants registered as receivers, using the
       
   300 	 * specified timeStamp, sequence number and the current payload type
       
   301 	 * specified for the session.
       
   302 	 * 
       
   303 	 * @param buf
       
   304 	 *            A buffer of bytes, less than 1496 bytes
       
   305 	 * @param rtpTimestamp
       
   306 	 *            the RTP timestamp to be used in the packet
       
   307 	 * @param seqNum
       
   308 	 *            the sequence number to be used in the packet
       
   309 	 * @return null if there was a problem, {RTP Timestamp, Sequence number}
       
   310 	 *         otherwise
       
   311 	 */
       
   312 	public long[] sendData(byte[] buf, long rtpTimestamp, long seqNum) {
       
   313 		byte[][] tmp = { buf };
       
   314 		long[][] ret = this.sendData(tmp, null, null, -1, null);
       
   315 
       
   316 		if (ret != null)
       
   317 			return ret[0];
       
   318 
       
   319 		return null;
       
   320 	}
       
   321 
       
   322 	/**
       
   323 	 * Send data to all participants registered as receivers, using the current
       
   324 	 * timeStamp and payload type. The RTP timestamp will be the same for all
       
   325 	 * the packets.
       
   326 	 * 
       
   327 	 * @param buffers
       
   328 	 *            A buffer of bytes, should not bed padded and less than 1500
       
   329 	 *            bytes on most networks.
       
   330 	 * @param csrcArray
       
   331 	 *            an array with the SSRCs of contributing sources
       
   332 	 * @param markers
       
   333 	 *            An array indicating what packets should be marked. Rarely
       
   334 	 *            anything but the first one
       
   335 	 * @param rtpTimestamp
       
   336 	 *            The RTP timestamp to be applied to all packets
       
   337 	 * @param seqNumbers
       
   338 	 *            An array with the sequence number associated with each byte[]
       
   339 	 * @return null if there was a problem sending the packets, 2-dim array with
       
   340 	 *         {RTP Timestamp, Sequence number}
       
   341 	 */
       
   342 	public long[][] sendData(byte[][] buffers, long[] csrcArray,
       
   343 			boolean[] markers, long rtpTimestamp, long[] seqNumbers) {
       
   344 		if (RTPSession.rtpDebugLevel > 5) {
       
   345 			System.out.println("-> RTPSession.sendData(byte[])");
       
   346 		}
       
   347 
       
   348 		// Same RTP timestamp for all
       
   349 		if (rtpTimestamp < 0)
       
   350 			rtpTimestamp = System.currentTimeMillis();
       
   351 
       
   352 		// Return values
       
   353 		long[][] ret = new long[buffers.length][2];
       
   354 
       
   355 		for (int i = 0; i < buffers.length; i++) {
       
   356 			byte[] buf = buffers[i];
       
   357 
       
   358 			boolean marker = false;
       
   359 			if (markers != null)
       
   360 				marker = markers[i];
       
   361 
       
   362 			if (buf.length > 1500) {
       
   363 				System.out
       
   364 				.println("RTPSession.sendData() called with buffer exceeding 1500 bytes ("
       
   365 						+ buf.length + ")");
       
   366 			}
       
   367 
       
   368 			// Get the return values
       
   369 			ret[i][0] = rtpTimestamp;
       
   370 			if (seqNumbers == null) {
       
   371 				ret[i][1] = getNextSeqNum();
       
   372 			} else {
       
   373 				ret[i][1] = seqNumbers[i];
       
   374 			}
       
   375 			// Create a new RTP Packet
       
   376 			RtpPkt pkt = RtpPktPool.getInstance().borrowPkt();
       
   377 			pkt.initPacket(rtpTimestamp, this.ssrc, (int) ret[i][1],
       
   378 					this.payloadType, buf);
       
   379 
       
   380 			if (csrcArray != null)
       
   381 				pkt.setCsrcs(csrcArray);
       
   382 
       
   383 			pkt.setMarked(marker);
       
   384 
       
   385 			// Creates a raw packet
       
   386 			byte[] pktBytes = pkt.encode();
       
   387 
       
   388 			// System.out.println(Integer.toString(StaticProcs.bytesToUIntInt(pktBytes,
       
   389 			// 2)));
       
   390 
       
   391 			// Pre-flight check, are resolving an SSRC conflict?
       
   392 			if (this.conflict) {
       
   393 				System.out
       
   394 				.println("RTPSession.sendData() called while trying to resolve conflict.");
       
   395 				return null;
       
   396 			}
       
   397 
       
   398 			if (this.mcSession) {
       
   399 				DatagramPacket packet = null;
       
   400 
       
   401 				try {
       
   402 					packet = new DatagramPacket(pktBytes, pktBytes.length,
       
   403 							this.mcGroup, this.rtpMCSock.getPort());
       
   404 				} catch (Exception e) {
       
   405 					System.out
       
   406 					.println("RTPSession.sendData() packet creation failed.");
       
   407 					e.printStackTrace();
       
   408 					return null;
       
   409 				}
       
   410 
       
   411 				try {
       
   412 					rtpMCSock.send(packet);
       
   413 					// Debug
       
   414 					if (this.debugAppIntf != null) {
       
   415 						this.debugAppIntf.packetSent(1,
       
   416 								(InetSocketAddress) packet.getSocketAddress(),
       
   417 								new String("Sent multicast RTP packet of size "
       
   418 										+ packet.getLength()
       
   419 										+ " to "
       
   420 										+ packet.getSocketAddress().toString()
       
   421 										+ " via "
       
   422 										+ rtpMCSock.getLocalSocketAddress()
       
   423 										.toString()));
       
   424 					}
       
   425 				} catch (Exception e) {
       
   426 					System.out
       
   427 					.println("RTPSession.sendData() multicast failed.");
       
   428 					e.printStackTrace();
       
   429 					return null;
       
   430 				}
       
   431 
       
   432 			} else {
       
   433 				// Loop over recipients
       
   434 				Iterator<Participant> iter = partDb.getUnicastReceivers();
       
   435 				while (iter.hasNext()) {
       
   436 					InetSocketAddress receiver = iter.next().rtpAddress;
       
   437 					DatagramPacket packet = null;
       
   438 
       
   439 					if (RTPSession.rtpDebugLevel > 15) {
       
   440 						System.out.println("   Sending to "
       
   441 								+ receiver.toString());
       
   442 					}
       
   443 
       
   444 					try {
       
   445 						packet = new DatagramPacket(pktBytes, pktBytes.length,
       
   446 								receiver);
       
   447 					} catch (Exception e) {
       
   448 						System.out
       
   449 						.println("RTPSession.sendData() packet creation failed.");
       
   450 						e.printStackTrace();
       
   451 						return null;
       
   452 					}
       
   453 
       
   454 					// Actually send the packet
       
   455 					try {
       
   456 						rtpSock.send(packet);
       
   457 						// Debug
       
   458 						if (this.debugAppIntf != null) {
       
   459 							this.debugAppIntf
       
   460 							.packetSent(
       
   461 									0,
       
   462 									(InetSocketAddress) packet
       
   463 									.getSocketAddress(),
       
   464 									new String(
       
   465 											"Sent unicast RTP packet of size "
       
   466 											+ packet
       
   467 											.getLength()
       
   468 											+ " to "
       
   469 											+ packet
       
   470 											.getSocketAddress()
       
   471 											.toString()
       
   472 											+ " via "
       
   473 											+ rtpSock
       
   474 											.getLocalSocketAddress()
       
   475 											.toString()));
       
   476 						}
       
   477 					} catch (Exception e) {
       
   478 						System.out
       
   479 						.println("RTPSession.sendData() unicast failed.");
       
   480 						e.printStackTrace();
       
   481 						return null;
       
   482 					}
       
   483 				}
       
   484 			}
       
   485 
       
   486 			// Update our stats
       
   487 			this.sentPktCount++;
       
   488 			this.sentOctetCount++;
       
   489 
       
   490 			if (RTPSession.rtpDebugLevel > 5) {
       
   491 				System.out.println("<- RTPSession.sendData(byte[]) "
       
   492 						+ pkt.getSeqNumber());
       
   493 			}
       
   494 		}
       
   495 
       
   496 		return ret;
       
   497 	}
       
   498 
       
   499 	public void sendData(DatagramPacket packet, RtpPkt pkt) {
       
   500 		if (RTPSession.rtpDebugLevel > 5) {
       
   501 			System.out.println("-> RTPSession.sendData(byte[])");
       
   502 		}
       
   503 
       
   504 		pkt.setTimeStamp(System.currentTimeMillis());
       
   505 		pkt.setSsrc(ssrc);
       
   506 		pkt.setSeqNumber(getNextSeqNum());
       
   507 
       
   508 		// Creates a raw packet
       
   509 		pkt.writeHeader();
       
   510 
       
   511 		// Pre-flight check, are resolving an SSRC conflict?
       
   512 		if (this.conflict) {
       
   513 			System.out
       
   514 			.println("RTPSession.sendData() called while trying to resolve conflict.");
       
   515 			return;
       
   516 		}
       
   517 
       
   518 		if (this.mcSession) {
       
   519 			try {
       
   520 				packet.setPort(this.rtpMCSock.getPort());
       
   521 				packet.setAddress(this.mcGroup);
       
   522 			} catch (Exception e) {
       
   523 				System.out
       
   524 				.println("RTPSession.sendData() packet creation failed.");
       
   525 				e.printStackTrace();
       
   526 				return;
       
   527 			}
       
   528 			try {
       
   529 				rtpMCSock.send(packet);
       
   530 				// Debug
       
   531 				if (this.debugAppIntf != null) {
       
   532 					this.debugAppIntf.packetSent(1,
       
   533 							(InetSocketAddress) packet.getSocketAddress(),
       
   534 							new String("Sent multicast RTP packet of size "
       
   535 									+ packet.getLength()
       
   536 									+ " to "
       
   537 									+ packet.getSocketAddress().toString()
       
   538 									+ " via "
       
   539 									+ rtpMCSock.getLocalSocketAddress()
       
   540 									.toString()));
       
   541 				}
       
   542 			} catch (Exception e) {
       
   543 				System.out
       
   544 				.println("RTPSession.sendData() multicast failed.");
       
   545 				e.printStackTrace();
       
   546 				return;
       
   547 			}
       
   548 
       
   549 		} else {
       
   550 			try {
       
   551 				packet.setSocketAddress(firstPart.rtpAddress);
       
   552 			} catch (Exception e) {
       
   553 				System.out
       
   554 				.println("RTPSession.sendData() packet creation failed.");
       
   555 				e.printStackTrace();
       
   556 				return;
       
   557 			}
       
   558 
       
   559 			// Actually send the packet
       
   560 			try {
       
   561 				
       
   562 				rtpSock.send(packet);
       
   563 				Log.d("RTP", "packet");
       
   564 				// Debug
       
   565 				if (this.debugAppIntf != null) {
       
   566 					this.debugAppIntf
       
   567 					.packetSent(
       
   568 							0,
       
   569 							(InetSocketAddress) packet
       
   570 							.getSocketAddress(),
       
   571 							new String(
       
   572 									"Sent unicast RTP packet of size "
       
   573 									+ packet
       
   574 									.getLength()
       
   575 									+ " to "
       
   576 									+ packet
       
   577 									.getSocketAddress()
       
   578 									.toString()
       
   579 									+ " via "
       
   580 									+ rtpSock
       
   581 									.getLocalSocketAddress()
       
   582 									.toString()));
       
   583 				}
       
   584 			} catch (Exception e) {
       
   585 				System.out
       
   586 				.println("RTPSession.sendData() unicast failed.");
       
   587 				e.printStackTrace();
       
   588 				return;
       
   589 			}
       
   590 		}
       
   591 
       
   592 		// Update our stats
       
   593 		this.sentPktCount++;
       
   594 		this.sentOctetCount++;
       
   595 		if (RTPSession.rtpDebugLevel > 5) {
       
   596 			System.out.println("<- RTPSession.sendData(byte[]) "
       
   597 					+ pkt.getSeqNumber());
       
   598 		}
       
   599 	}
       
   600 
       
   601 	/**
       
   602 	 * Send RTCP App packet to receiver specified by ssrc
       
   603 	 * 
       
   604 	 * 
       
   605 	 * 
       
   606 	 * Return values: 0 okay -1 no RTCP session established -2 name is not
       
   607 	 * byte[4]; -3 data is not byte[x], where x = 4*y for syme y -4 type is not
       
   608 	 * a 5 bit unsigned integer
       
   609 	 * 
       
   610 	 * Note that a return value of 0 does not guarantee delivery. The
       
   611 	 * participant must also exist in the participant database, otherwise the
       
   612 	 * message will eventually be deleted.
       
   613 	 * 
       
   614 	 * @param ssrc
       
   615 	 *            of the participant you want to reach
       
   616 	 * @param type
       
   617 	 *            the RTCP App packet subtype, default 0
       
   618 	 * @param name
       
   619 	 *            the ASCII (in byte[4]) representation
       
   620 	 * @param data
       
   621 	 *            the data itself
       
   622 	 * @return 0 if okay, negative value otherwise (see above)
       
   623 	 */
       
   624 
       
   625 	public int sendRTCPAppPacket(long ssrc, int type, byte[] name, byte[] data) {
       
   626 		if (this.rtcpSession == null)
       
   627 			return -1;
       
   628 
       
   629 		if (name.length != 4)
       
   630 			return -2;
       
   631 
       
   632 		if (data.length % 4 != 0)
       
   633 			return -3;
       
   634 
       
   635 		if (type > 63 || type < 0)
       
   636 			return -4;
       
   637 
       
   638 		RtcpPktAPP pkt = new RtcpPktAPP(ssrc, type, name, data);
       
   639 		this.rtcpSession.addToAppQueue(ssrc, pkt);
       
   640 
       
   641 		return 0;
       
   642 	}
       
   643 
       
   644 	/**
       
   645 	 * Add a participant object to the participant database.
       
   646 	 * 
       
   647 	 * If packets have already been received from this user, we will try to
       
   648 	 * update the automatically inserted participant with the information
       
   649 	 * provided here.
       
   650 	 * 
       
   651 	 * @param p
       
   652 	 *            A participant.
       
   653 	 */
       
   654 	public int addParticipant(Participant p) {
       
   655 		// For now we make all participants added this way persistent
       
   656 		firstPart = p;
       
   657 		p.unexpected = false;
       
   658 		return this.partDb.addParticipant(0, p);
       
   659 	}
       
   660 
       
   661 	/**
       
   662 	 * Remove a participant from the database. All buffered packets will be
       
   663 	 * destroyed.
       
   664 	 * 
       
   665 	 * @param p
       
   666 	 *            A participant.
       
   667 	 */
       
   668 	public void removeParticipant(Participant p) {
       
   669 		partDb.removeParticipant(p);
       
   670 	}
       
   671 
       
   672 	public Iterator<Participant> getUnicastReceivers() {
       
   673 		return partDb.getUnicastReceivers();
       
   674 	}
       
   675 
       
   676 	public Enumeration<Participant> getParticipants() {
       
   677 		return partDb.getParticipants();
       
   678 	}
       
   679 
       
   680 	/**
       
   681 	 * End the RTP Session. This will halt all threads and send bye-messages to
       
   682 	 * other participants.
       
   683 	 * 
       
   684 	 * RTCP related threads may require several seconds to wake up and
       
   685 	 * terminate.
       
   686 	 */
       
   687 	public void endSession() {
       
   688 		this.endSession = true;
       
   689 
       
   690 		// No more RTP packets, please
       
   691 		if (this.mcSession) {
       
   692 			this.rtpMCSock.close();
       
   693 		} else {
       
   694 			this.rtpSock.close();
       
   695 		}
       
   696 
       
   697 		// Signal the thread that pushes data to application
       
   698 		this.pktBufLock.lock();
       
   699 		try {
       
   700 			this.pktBufDataReady.signalAll();
       
   701 		} finally {
       
   702 			this.pktBufLock.unlock();
       
   703 		}
       
   704 		// Interrupt what may be sleeping
       
   705 		//this.rtcpSession.senderThrd.interrupt();
       
   706 
       
   707 		// Give things a chance to cool down.
       
   708 		try {
       
   709 			Thread.sleep(50);
       
   710 		} catch (Exception e) {
       
   711 		}
       
   712 		;
       
   713 
       
   714 		this.appCallerThrd.interrupt();
       
   715 
       
   716 		// Give things a chance to cool down.
       
   717 		try {
       
   718 			Thread.sleep(50);
       
   719 		} catch (Exception e) {
       
   720 		}
       
   721 		;
       
   722 
       
   723 		if (this.rtcpSession != null) {
       
   724 			// No more RTP packets, please
       
   725 			if (this.mcSession) {
       
   726 				this.rtcpSession.rtcpMCSock.close();
       
   727 			} else {
       
   728 				this.rtcpSession.rtcpSock.close();
       
   729 			}
       
   730 		}
       
   731 		DatagramPool.removeInstance();
       
   732 		PktBufNodePool.removeInstance();
       
   733 		DataFramePool.removeInstance();
       
   734 		RtpPktPool.removeInstance();
       
   735 	}
       
   736 
       
   737 	/**
       
   738 	 * Check whether this session is ending.
       
   739 	 * 
       
   740 	 * @return true if session and associated threads are terminating.
       
   741 	 */
       
   742 	boolean isEnding() {
       
   743 		return this.endSession;
       
   744 	}
       
   745 
       
   746 	/**
       
   747 	 * Overrides CNAME, used for outgoing RTCP packets.
       
   748 	 * 
       
   749 	 * @param cname
       
   750 	 *            a string, e.g. username@hostname. Must be unique for session.
       
   751 	 */
       
   752 	public void CNAME(String cname) {
       
   753 		this.cname = cname;
       
   754 	}
       
   755 
       
   756 	/**
       
   757 	 * Get the current CNAME, used for outgoing SDES packets
       
   758 	 */
       
   759 	public String CNAME() {
       
   760 		return this.cname;
       
   761 	}
       
   762 
       
   763 	public long getSsrc() {
       
   764 		return this.ssrc;
       
   765 	}
       
   766 
       
   767 	private void generateCNAME() {
       
   768 		String hostname;
       
   769 
       
   770 		if (this.mcSession) {
       
   771 			hostname = this.rtpMCSock.getLocalAddress().getCanonicalHostName();
       
   772 		} else {
       
   773 			hostname = this.rtpSock.getLocalAddress().getCanonicalHostName();
       
   774 		}
       
   775 
       
   776 		// if(hostname.equals("0.0.0.0") && System.getenv("HOSTNAME") != null) {
       
   777 		// hostname = System.getenv("HOSTNAME");
       
   778 		// }
       
   779 
       
   780 		cname = System.getProperty("user.name") + "@" + hostname;
       
   781 	}
       
   782 
       
   783 	/**
       
   784 	 * Change the RTP socket of the session. Peers must be notified through SIP
       
   785 	 * or other signalling protocol. Only valid if this is a unicast session to
       
   786 	 * begin with.
       
   787 	 * 
       
   788 	 * @param newSock
       
   789 	 *            integer for new port number, check it is free first.
       
   790 	 */
       
   791 	public int updateRTPSock(DatagramSocket newSock) {
       
   792 		if (!mcSession) {
       
   793 			rtpSock = newSock;
       
   794 			return 0;
       
   795 		} else {
       
   796 			System.out.println("Can't switch from multicast to unicast.");
       
   797 			return -1;
       
   798 		}
       
   799 	}
       
   800 
       
   801 	/**
       
   802 	 * Change the RTCP socket of the session. Peers must be notified through SIP
       
   803 	 * or other signalling protocol. Only valid if this is a unicast session to
       
   804 	 * begin with.
       
   805 	 * 
       
   806 	 * @param newSock
       
   807 	 *            the new unicast socket for RTP communication.
       
   808 	 */
       
   809 	public int updateRTCPSock(DatagramSocket newSock) {
       
   810 		if (!mcSession) {
       
   811 			this.rtcpSession.rtcpSock = newSock;
       
   812 			return 0;
       
   813 		} else {
       
   814 			System.out.println("Can't switch from multicast to unicast.");
       
   815 			return -1;
       
   816 		}
       
   817 	}
       
   818 
       
   819 	/**
       
   820 	 * Change the RTP multicast socket of the session. Peers must be notified
       
   821 	 * through SIP or other signalling protocol. Only valid if this is a
       
   822 	 * multicast session to begin with.
       
   823 	 * 
       
   824 	 * @param newSock
       
   825 	 *            the new multicast socket for RTP communication.
       
   826 	 */
       
   827 	public int updateRTPSock(MulticastSocket newSock) {
       
   828 		if (mcSession) {
       
   829 			this.rtpMCSock = newSock;
       
   830 			return 0;
       
   831 		} else {
       
   832 			System.out.println("Can't switch from unicast to multicast.");
       
   833 			return -1;
       
   834 		}
       
   835 	}
       
   836 
       
   837 	/**
       
   838 	 * Change the RTCP multicast socket of the session. Peers must be notified
       
   839 	 * through SIP or other signalling protocol. Only valid if this is a
       
   840 	 * multicast session to begin with.
       
   841 	 * 
       
   842 	 * @param newSock
       
   843 	 *            the new multicast socket for RTCP communication.
       
   844 	 */
       
   845 	public int updateRTCPSock(MulticastSocket newSock) {
       
   846 		if (mcSession) {
       
   847 			this.rtcpSession.rtcpMCSock = newSock;
       
   848 			return 0;
       
   849 		} else {
       
   850 			System.out.println("Can't switch from unicast to multicast.");
       
   851 			return -1;
       
   852 		}
       
   853 	}
       
   854 
       
   855 	/**
       
   856 	 * Update the payload type used for the session. It is represented as a 7
       
   857 	 * bit integer, whose meaning must be negotiated elsewhere (see IETF RFCs <a
       
   858 	 * href="http://www.ietf.org/rfc/rfc3550.txt">3550</a> and <a
       
   859 	 * href="http://www.ietf.org/rfc/rfc3550.txt">3551</a>)
       
   860 	 * 
       
   861 	 * @param payloadT
       
   862 	 *            an integer representing the payload type of any subsequent
       
   863 	 *            packets that are sent.
       
   864 	 */
       
   865 	public int payloadType(int payloadT) {
       
   866 		if (payloadT > 128 || payloadT < 0) {
       
   867 			return -1;
       
   868 		} else {
       
   869 			this.payloadType = payloadT;
       
   870 			return this.payloadType;
       
   871 		}
       
   872 	}
       
   873 
       
   874 	/**
       
   875 	 * Get the payload type that is currently used for outgoing RTP packets.
       
   876 	 * 
       
   877 	 * @return payload type as integer
       
   878 	 */
       
   879 	public int payloadType() {
       
   880 		return this.payloadType;
       
   881 	}
       
   882 
       
   883 	/**
       
   884 	 * Should packets from unknown participants be returned to the application?
       
   885 	 * This can be dangerous.
       
   886 	 * 
       
   887 	 * @param doAccept
       
   888 	 *            packets from participants not added by the application.
       
   889 	 */
       
   890 	public void naivePktReception(boolean doAccept) {
       
   891 		naiveReception = doAccept;
       
   892 	}
       
   893 
       
   894 	/**
       
   895 	 * Are packets from unknown participants returned to the application?
       
   896 	 * 
       
   897 	 * @return whether we accept packets from participants not added by the
       
   898 	 *         application.
       
   899 	 */
       
   900 	public boolean naivePktReception() {
       
   901 		return naiveReception;
       
   902 	}
       
   903 
       
   904 	/**
       
   905 	 * Set the number of RTP packets that should be buffered when a packet is
       
   906 	 * missing or received out of order. Setting this number high increases the
       
   907 	 * chance of correctly reordering packets, but increases latency when a
       
   908 	 * packet is dropped by the network.
       
   909 	 * 
       
   910 	 * Packets that arrive in order are not affected, they are passed straight
       
   911 	 * to the application.
       
   912 	 * 
       
   913 	 * The maximum delay is numberofPackets * packet rate , where the packet
       
   914 	 * rate depends on the codec and profile used by the sender.
       
   915 	 * 
       
   916 	 * Valid values: >0 - The maximum number of packets (based on RTP Timestamp)
       
   917 	 * that may accumulate 0 - All valid packets received in order will be given
       
   918 	 * to the application -1 - All valid packets will be given to the
       
   919 	 * application
       
   920 	 * 
       
   921 	 * @param behavior
       
   922 	 *            the be
       
   923 	 * @return the behavior set, unchanged in the case of a erroneous value
       
   924 	 */
       
   925 	public int packetBufferBehavior(int behavior) {
       
   926 		if (behavior > -2) {
       
   927 			this.pktBufBehavior = behavior;
       
   928 			// Signal the thread that pushes data to application
       
   929 			this.pktBufLock.lock();
       
   930 			try {
       
   931 				this.pktBufDataReady.signalAll();
       
   932 			} finally {
       
   933 				this.pktBufLock.unlock();
       
   934 			}
       
   935 			return this.pktBufBehavior;
       
   936 		} else {
       
   937 			return this.pktBufBehavior;
       
   938 		}
       
   939 	}
       
   940 
       
   941 	/**
       
   942 	 * The number of RTP packets that should be buffered when a packet is
       
   943 	 * missing or received out of order. A high number increases the chance of
       
   944 	 * correctly reordering packets, but increases latency when a packet is
       
   945 	 * dropped by the network.
       
   946 	 * 
       
   947 	 * A negative value disables the buffering, out of order packets will simply
       
   948 	 * be dropped.
       
   949 	 * 
       
   950 	 * @return the maximum number of packets that can accumulate before the
       
   951 	 *         first is returned
       
   952 	 */
       
   953 	public int packetBufferBehavior() {
       
   954 		return this.pktBufBehavior;
       
   955 	}
       
   956 
       
   957 	/**
       
   958 	 * Set whether the stack should operate in RFC 4585 mode.
       
   959 	 * 
       
   960 	 * This will automatically call adjustPacketBufferBehavior(-1), i.e. disable
       
   961 	 * all RTP packet buffering in jlibrtp, and disable frame reconstruction
       
   962 	 * 
       
   963 	 * @param rtcpAVPFIntf
       
   964 	 *            the in
       
   965 	 */
       
   966 	public int registerAVPFIntf(RTCPAVPFIntf rtcpAVPFIntf, int maxDelay,
       
   967 			int earlyThreshold, int regularThreshold) {
       
   968 		if (this.rtcpSession != null) {
       
   969 			this.packetBufferBehavior(-1);
       
   970 			this.frameReconstruction = false;
       
   971 			this.rtcpAVPFIntf = rtcpAVPFIntf;
       
   972 			this.fbEarlyThreshold = earlyThreshold;
       
   973 			this.fbRegularThreshold = regularThreshold;
       
   974 			return 0;
       
   975 		} else {
       
   976 			return -1;
       
   977 		}
       
   978 	}
       
   979 
       
   980 	/**
       
   981 	 * Unregisters the RTCP AVPF interface, thereby going from RFC 4585 mode to
       
   982 	 * RFC 3550
       
   983 	 * 
       
   984 	 * You still have to adjust packetBufferBehavior() and frameReconstruction.
       
   985 	 * 
       
   986 	 */
       
   987 	public void unregisterAVPFIntf() {
       
   988 		this.fbEarlyThreshold = -1;
       
   989 		this.fbRegularThreshold = -1;
       
   990 		this.rtcpAVPFIntf = null;
       
   991 	}
       
   992 
       
   993 	/**
       
   994 	 * Enable / disable frame reconstruction in the packet buffers. This is only
       
   995 	 * relevant if getPacketBufferBehavior > 0;
       
   996 	 * 
       
   997 	 * Default is true.
       
   998 	 */
       
   999 	public void frameReconstruction(boolean toggle) {
       
  1000 		this.frameReconstruction = toggle;
       
  1001 	}
       
  1002 
       
  1003 	/**
       
  1004 	 * Whether the packet buffer will attempt to reconstruct packet
       
  1005 	 * automatically.
       
  1006 	 * 
       
  1007 	 * @return the status
       
  1008 	 */
       
  1009 	public boolean frameReconstruction() {
       
  1010 		return this.frameReconstruction;
       
  1011 	}
       
  1012 
       
  1013 	/**
       
  1014 	 * The bandwidth currently allocated to the session, in bytes per second.
       
  1015 	 * The default is 8000.
       
  1016 	 * 
       
  1017 	 * This value is not enforced and currently only used to calculate the RTCP
       
  1018 	 * interval to ensure the control messages do not exceed 5% of the total
       
  1019 	 * bandwidth described here.
       
  1020 	 * 
       
  1021 	 * Since the actual value may change a conservative estimate should be used
       
  1022 	 * to avoid RTCP flooding.
       
  1023 	 * 
       
  1024 	 * see rtcpBandwidth(void)
       
  1025 	 * 
       
  1026 	 * @return current bandwidth setting
       
  1027 	 */
       
  1028 	public int sessionBandwidth() {
       
  1029 		return this.bandwidth;
       
  1030 	}
       
  1031 
       
  1032 	/**
       
  1033 	 * Set the bandwidth of the session.
       
  1034 	 * 
       
  1035 	 * See sessionBandwidth(void) for details.
       
  1036 	 * 
       
  1037 	 * @param bandwidth
       
  1038 	 *            the new value requested, in bytes per second
       
  1039 	 * @return the actual value set
       
  1040 	 */
       
  1041 	public int sessionBandwidth(int bandwidth) {
       
  1042 		if (bandwidth < 1) {
       
  1043 			this.bandwidth = 8000;
       
  1044 		} else {
       
  1045 			this.bandwidth = bandwidth;
       
  1046 		}
       
  1047 		return this.bandwidth;
       
  1048 	}
       
  1049 
       
  1050 	/**
       
  1051 	 * RFC 3550 dictates that 5% of the total bandwidth, as set by
       
  1052 	 * sessionBandwidth, should be dedicated to RTCP traffic. This
       
  1053 	 * 
       
  1054 	 * This should normally not be done, but is permissible in conjunction with
       
  1055 	 * feedback (RFC 4585) and possibly other profiles.
       
  1056 	 * 
       
  1057 	 * Also see sessionBandwidth(void)
       
  1058 	 * 
       
  1059 	 * @return current RTCP bandwidth setting, -1 means not in use
       
  1060 	 */
       
  1061 	public int rtcpBandwidth() {
       
  1062 		return this.rtcpBandwidth;
       
  1063 	}
       
  1064 
       
  1065 	/**
       
  1066 	 * Set the RTCP bandwidth, see rtcpBandwidth(void) for details.
       
  1067 	 * 
       
  1068 	 * This function must be
       
  1069 	 * 
       
  1070 	 * @param bandwidth
       
  1071 	 *            the new value requested, in bytes per second or -1 to disable
       
  1072 	 * @return the actual value set
       
  1073 	 */
       
  1074 	public int rtcpBandwidth(int bandwidth) {
       
  1075 		if (bandwidth < -1) {
       
  1076 			this.rtcpBandwidth = -1;
       
  1077 		} else {
       
  1078 			this.rtcpBandwidth = bandwidth;
       
  1079 		}
       
  1080 		return this.rtcpBandwidth;
       
  1081 	}
       
  1082 
       
  1083 	/********************************************* Feedback message stuff ***************************************/
       
  1084 
       
  1085 	/**
       
  1086 	 * Adds a Picture Loss Indication to the feedback queue
       
  1087 	 * 
       
  1088 	 * @param ssrcMediaSource
       
  1089 	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
       
  1090 	 */
       
  1091 	public int fbPictureLossIndication(long ssrcMediaSource) {
       
  1092 		int ret = 0;
       
  1093 
       
  1094 		if (this.rtcpAVPFIntf == null)
       
  1095 			return -1;
       
  1096 
       
  1097 		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
       
  1098 		pkt.makePictureLossIndication();
       
  1099 		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
       
  1100 		if (ret == 0)
       
  1101 			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
       
  1102 		return ret;
       
  1103 	}
       
  1104 
       
  1105 	/**
       
  1106 	 * Adds a Slice Loss Indication to the feedback queue
       
  1107 	 * 
       
  1108 	 * @param ssrcMediaSource
       
  1109 	 * @param sliFirst
       
  1110 	 *            macroblock (MB) address of the first lost macroblock
       
  1111 	 * @param sliNumber
       
  1112 	 *            number of lost macroblocks
       
  1113 	 * @param sliPictureId
       
  1114 	 *            six least significant bits of the codec-specific identif
       
  1115 	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
       
  1116 	 */
       
  1117 	public int fbSlicLossIndication(long ssrcMediaSource, int[] sliFirst,
       
  1118 			int[] sliNumber, int[] sliPictureId) {
       
  1119 		int ret = 0;
       
  1120 		if (this.rtcpAVPFIntf == null)
       
  1121 			return -1;
       
  1122 
       
  1123 		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
       
  1124 		pkt.makeSliceLossIndication(sliFirst, sliNumber, sliPictureId);
       
  1125 
       
  1126 		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
       
  1127 		if (ret == 0)
       
  1128 			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
       
  1129 		return ret;
       
  1130 	}
       
  1131 
       
  1132 	/**
       
  1133 	 * Adds a Reference Picture Selection Indication to the feedback queue
       
  1134 	 * 
       
  1135 	 * @param ssrcMediaSource
       
  1136 	 * @param bitPadding
       
  1137 	 *            number of padded bits at end of bitString
       
  1138 	 * @param payloadType
       
  1139 	 *            RTP payload type for codec
       
  1140 	 * @param bitString
       
  1141 	 *            RPSI information as natively defined by the video codec
       
  1142 	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
       
  1143 	 */
       
  1144 	public int fbRefPictureSelIndic(long ssrcMediaSource, int bitPadding,
       
  1145 			int payloadType, byte[] bitString) {
       
  1146 		int ret = 0;
       
  1147 
       
  1148 		if (this.rtcpAVPFIntf == null)
       
  1149 			return -1;
       
  1150 
       
  1151 		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
       
  1152 		pkt.makeRefPictureSelIndic(bitPadding, payloadType, bitString);
       
  1153 		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
       
  1154 		if (ret == 0)
       
  1155 			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
       
  1156 		return ret;
       
  1157 	}
       
  1158 
       
  1159 	/**
       
  1160 	 * Adds a Picture Loss Indication to the feedback queue
       
  1161 	 * 
       
  1162 	 * @param ssrcMediaSource
       
  1163 	 * @param bitString
       
  1164 	 *            the original application message
       
  1165 	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
       
  1166 	 */
       
  1167 	public int fbAppLayerFeedback(long ssrcMediaSource, byte[] bitString) {
       
  1168 		int ret = 0;
       
  1169 
       
  1170 		if (this.rtcpAVPFIntf == null)
       
  1171 			return -1;
       
  1172 
       
  1173 		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
       
  1174 		pkt.makeAppLayerFeedback(bitString);
       
  1175 		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
       
  1176 		if (ret == 0)
       
  1177 			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
       
  1178 		return ret;
       
  1179 	}
       
  1180 
       
  1181 	/**
       
  1182 	 * Adds a RTP Feedback packet to the feedback queue.
       
  1183 	 * 
       
  1184 	 * These are mostly used for NACKs.
       
  1185 	 * 
       
  1186 	 * @param ssrcMediaSource
       
  1187 	 * @param FMT
       
  1188 	 *            the Feedback Message Subtype
       
  1189 	 * @param PID
       
  1190 	 *            RTP sequence numbers of lost packets
       
  1191 	 * @param BLP
       
  1192 	 *            bitmask of following lost packets, shared index with PID
       
  1193 	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
       
  1194 	 */
       
  1195 	public int fbPictureLossIndication(long ssrcMediaSource, int FMT,
       
  1196 			int[] PID, int[] BLP) {
       
  1197 		int ret = 0;
       
  1198 
       
  1199 		if (this.rtcpAVPFIntf == null)
       
  1200 			return -1;
       
  1201 
       
  1202 		RtcpPktRTPFB pkt = new RtcpPktRTPFB(this.ssrc, ssrcMediaSource, FMT,
       
  1203 				PID, BLP);
       
  1204 		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
       
  1205 		if (ret == 0)
       
  1206 			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
       
  1207 		return ret;
       
  1208 	}
       
  1209 
       
  1210 	/**
       
  1211 	 * Fetches the next sequence number for RTP packets.
       
  1212 	 * 
       
  1213 	 * @return the next sequence number
       
  1214 	 */
       
  1215 	private int getNextSeqNum() {
       
  1216 		seqNum++;
       
  1217 		// 16 bit number
       
  1218 		if (seqNum > 65536) {
       
  1219 			seqNum = 0;
       
  1220 		}
       
  1221 		return seqNum;
       
  1222 	}
       
  1223 
       
  1224 	/**
       
  1225 	 * Initializes a random variable
       
  1226 	 * 
       
  1227 	 */
       
  1228 	private void createRandom() {
       
  1229 		this.random = new Random(System.currentTimeMillis()
       
  1230 				+ Thread.currentThread().getId()
       
  1231 				- Thread.currentThread().hashCode() + this.cname.hashCode());
       
  1232 	}
       
  1233 
       
  1234 	/**
       
  1235 	 * Generates a random sequence number
       
  1236 	 */
       
  1237 	private void generateSeqNum() {
       
  1238 		if (this.random == null)
       
  1239 			createRandom();
       
  1240 
       
  1241 		seqNum = this.random.nextInt();
       
  1242 		if (seqNum < 0)
       
  1243 			seqNum = -seqNum;
       
  1244 		while (seqNum > 65535) {
       
  1245 			seqNum = seqNum / 10;
       
  1246 		}
       
  1247 	}
       
  1248 
       
  1249 	/**
       
  1250 	 * Generates a random SSRC
       
  1251 	 */
       
  1252 	private void generateSsrc() {
       
  1253 		if (this.random == null)
       
  1254 			createRandom();
       
  1255 
       
  1256 		// Set an SSRC
       
  1257 		this.ssrc = this.random.nextInt();
       
  1258 		if (this.ssrc < 0) {
       
  1259 			this.ssrc = this.ssrc * -1;
       
  1260 		}
       
  1261 	}
       
  1262 
       
  1263 	/**
       
  1264 	 * Resolve an SSRC conflict.
       
  1265 	 * 
       
  1266 	 * Also increments the SSRC conflict counter, after 5 conflicts it is
       
  1267 	 * assumed there is a loop somewhere and the session will terminate.
       
  1268 	 * 
       
  1269 	 */
       
  1270 	protected void resolveSsrcConflict() {
       
  1271 		System.out
       
  1272 		.println("!!!!!!! Beginning SSRC conflict resolution !!!!!!!!!");
       
  1273 		this.conflictCount++;
       
  1274 
       
  1275 		if (this.conflictCount < 5) {
       
  1276 			// Don't send any more regular packets out until we have this sorted
       
  1277 			// out.
       
  1278 			this.conflict = true;
       
  1279 
       
  1280 			// Send byes
       
  1281 			rtcpSession.sendByes();
       
  1282 
       
  1283 			// Calculate the next delay
       
  1284 			rtcpSession.calculateDelay();
       
  1285 
       
  1286 			// Generate a new Ssrc for ourselves
       
  1287 			generateSsrc();
       
  1288 
       
  1289 			// Get the SDES packets out faster
       
  1290 			rtcpSession.initial = true;
       
  1291 
       
  1292 			this.conflict = false;
       
  1293 			System.out.println("SSRC conflict resolution complete");
       
  1294 
       
  1295 		} else {
       
  1296 			System.out
       
  1297 			.println("Too many conflicts. There is probably a loop in the network.");
       
  1298 			this.endSession();
       
  1299 		}
       
  1300 	}
       
  1301 }