src/jlibrtp/ParticipantDatabase.java
changeset 834 e8d6255306f8
parent 833 f5a5d9237d69
child 835 4e40f3481f23
equal deleted inserted replaced
833:f5a5d9237d69 834:e8d6255306f8
     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.util.Enumeration;
       
    22 import java.util.Iterator;
       
    23 import java.util.LinkedList;
       
    24 import java.util.concurrent.ConcurrentHashMap;
       
    25 
       
    26 /**
       
    27  * The participant database maintains three hashtables with participants.
       
    28  * 
       
    29  * The key issue is to be fast for operations that happen every time an RTP
       
    30  * packet is sent or received. We allow linear searching in cases where we need
       
    31  * to update participants with information.
       
    32  * 
       
    33  * The keying is therefore usually the SSRC. In cases where we have the cname,
       
    34  * but no SSRC is known (no SDES packet has been received), a simple hash i
       
    35  * calculated based on the CNAME. The RTCP code should, when receiving SDES
       
    36  * packets, check whether the participant is known and update the copy in this
       
    37  * database with SSRC if needed.
       
    38  * 
       
    39  * @author Arne Kepp
       
    40  */
       
    41 public class ParticipantDatabase {
       
    42 	/** The parent RTP Session */
       
    43 	RTPSession rtpSession = null;
       
    44 	/**
       
    45 	 * A linked list to hold participants explicitly added by the application In
       
    46 	 * unicast mode this is the list used for RTP and RTCP transmission, in
       
    47 	 * multicast it should not be in use.
       
    48 	 */
       
    49 	LinkedList<Participant> receivers = new LinkedList<Participant>();
       
    50 	/**
       
    51 	 * The hashtable holds participants added through received RTP and RTCP
       
    52 	 * packets, as well as participants that have been linked to an SSRC by ip
       
    53 	 * address (in unicast mode).
       
    54 	 */
       
    55 	ConcurrentHashMap<Long, Participant> ssrcTable = new ConcurrentHashMap<Long, Participant>();
       
    56 
       
    57 	/**
       
    58 	 * Simple constructor
       
    59 	 * 
       
    60 	 * @param parent
       
    61 	 *            parent RTPSession
       
    62 	 */
       
    63 	protected ParticipantDatabase(RTPSession parent) {
       
    64 		rtpSession = parent;
       
    65 	}
       
    66 
       
    67 	/**
       
    68 	 * 
       
    69 	 * @param cameFrom
       
    70 	 *            0: Application, 1: RTP packet, 2: RTCP
       
    71 	 * @param p
       
    72 	 *            the participant
       
    73 	 * @return 0 if okay, -1 if not
       
    74 	 */
       
    75 	protected int addParticipant(int cameFrom, Participant p) {
       
    76 		// Multicast or not?
       
    77 		if (this.rtpSession.mcSession) {
       
    78 			return this.addParticipantMulticast(cameFrom, p);
       
    79 		} else {
       
    80 			return this.addParticipantUnicast(cameFrom, p);
       
    81 		}
       
    82 
       
    83 	}
       
    84 
       
    85 	/**
       
    86 	 * Add a multicast participant to the database
       
    87 	 * 
       
    88 	 * @param cameFrom
       
    89 	 *            0: Application, 1,2: discovered through RTP or RTCP
       
    90 	 * @param p
       
    91 	 *            the participant to add
       
    92 	 * @return 0 if okay, -2 if redundant, -1 if adding participant to multicast
       
    93 	 */
       
    94 	private int addParticipantMulticast(int cameFrom, Participant p) {
       
    95 		if (cameFrom == 0) {
       
    96 			System.out
       
    97 					.println("ParticipantDatabase.addParticipant() doesnt expect"
       
    98 							+ " application to add participants to multicast session.");
       
    99 			return -1;
       
   100 		} else {
       
   101 			// Check this one is not redundant
       
   102 			if (this.ssrcTable.contains(p.ssrc)) {
       
   103 				System.out.println("ParticipantDatabase.addParticipant() SSRC "
       
   104 						+ "already known " + Long.toString(p.ssrc));
       
   105 				return -2;
       
   106 			} else {
       
   107 				this.ssrcTable.put(p.ssrc, p);
       
   108 				return 0;
       
   109 			}
       
   110 		}
       
   111 	}
       
   112 
       
   113 	/**
       
   114 	 * Add a unicast participant to the database
       
   115 	 * 
       
   116 	 * Result will be reported back through tpSession.appIntf.userEvent
       
   117 	 * 
       
   118 	 * @param cameFrom
       
   119 	 *            0: Application, 1,2: discovered through RTP or RTCP
       
   120 	 * @param p
       
   121 	 *            the participant to add
       
   122 	 * @return 0 if new, 1 if
       
   123 	 */
       
   124 	private int addParticipantUnicast(int cameFrom, Participant p) {
       
   125 		if (cameFrom == 0) {
       
   126 			// Check whether there is a match in the ssrcTable
       
   127 			boolean notDone = true;
       
   128 
       
   129 			Enumeration<Participant> enu = this.ssrcTable.elements();
       
   130 			while (notDone && enu.hasMoreElements()) {
       
   131 				Participant part = enu.nextElement();
       
   132 				if (part.unexpected
       
   133 						&& (part.rtcpReceivedFromAddress
       
   134 								.equals(part.rtcpAddress.getAddress()) || part.rtpReceivedFromAddress
       
   135 								.equals(part.rtpAddress.getAddress()))) {
       
   136 
       
   137 					part.rtpAddress = p.rtpAddress;
       
   138 					part.rtcpAddress = p.rtcpAddress;
       
   139 					part.unexpected = false;
       
   140 
       
   141 					// Report the match back to the application
       
   142 					Participant[] partArray = { part };
       
   143 					this.rtpSession.appIntf.userEvent(5, partArray);
       
   144 
       
   145 					notDone = false;
       
   146 					p = part;
       
   147 				}
       
   148 			}
       
   149 
       
   150 			// Add to the table of people that we send packets to
       
   151 			this.receivers.add(p);
       
   152 			return 0;
       
   153 
       
   154 		} else {
       
   155 			// Check whether there's a match in the receivers table
       
   156 			boolean notDone = true;
       
   157 			// System.out.println("GOT " + p.cname);
       
   158 			Iterator<Participant> iter = this.receivers.iterator();
       
   159 
       
   160 			while (notDone && iter.hasNext()) {
       
   161 				Participant part = iter.next();
       
   162 
       
   163 				// System.out.println(part.rtpAddress.getAddress().toString()
       
   164 				// + " " + part.rtcpAddress.getAddress().toString()
       
   165 				// + " " + p.rtpReceivedFromAddress.getAddress().toString()
       
   166 				// + " " + p.rtcpReceivedFromAddress.getAddress().toString());
       
   167 
       
   168 				// System.out.println(" HUUHHHH?  " +
       
   169 				// p.rtcpReceivedFromAddress.getAddress().equals(part.rtcpAddress.getAddress()));
       
   170 				if ((cameFrom == 1 && p.rtpReceivedFromAddress.getAddress()
       
   171 						.equals(part.rtpAddress.getAddress()))
       
   172 						|| (cameFrom == 2 && p.rtcpReceivedFromAddress
       
   173 								.getAddress().equals(
       
   174 										part.rtcpAddress.getAddress()))) {
       
   175 
       
   176 					part.rtpReceivedFromAddress = p.rtpReceivedFromAddress;
       
   177 					part.rtcpReceivedFromAddress = p.rtcpReceivedFromAddress;
       
   178 
       
   179 					// Move information
       
   180 					part.ssrc = p.ssrc;
       
   181 					part.cname = p.cname;
       
   182 					part.name = p.name;
       
   183 					part.loc = p.loc;
       
   184 					part.phone = p.phone;
       
   185 					part.email = p.email;
       
   186 					part.note = p.note;
       
   187 					part.tool = p.tool;
       
   188 					part.priv = p.priv;
       
   189 
       
   190 					this.ssrcTable.put(part.ssrc, part);
       
   191 
       
   192 					// Report the match back to the application
       
   193 					Participant[] partArray = { part };
       
   194 					this.rtpSession.appIntf.userEvent(5, partArray);
       
   195 					return 0;
       
   196 				}
       
   197 			}
       
   198 
       
   199 			// No match? ok
       
   200 			this.ssrcTable.put(p.ssrc, p);
       
   201 			return 0;
       
   202 		}
       
   203 	}
       
   204 
       
   205 	/**
       
   206 	 * Remove a participant from all tables
       
   207 	 * 
       
   208 	 * @param p
       
   209 	 *            the participant to be removed
       
   210 	 */
       
   211 	protected void removeParticipant(Participant p) {
       
   212 		if (!this.rtpSession.mcSession)
       
   213 			this.receivers.remove(p);
       
   214 
       
   215 		this.ssrcTable.remove(p.ssrc, p);
       
   216 	}
       
   217 
       
   218 	/**
       
   219 	 * Find a participant based on the ssrc
       
   220 	 * 
       
   221 	 * @param ssrc
       
   222 	 *            of the participant to be found
       
   223 	 * @return the participant, null if unknonw
       
   224 	 */
       
   225 	protected Participant getParticipant(long ssrc) {
       
   226 		Participant p = null;
       
   227 		p = ssrcTable.get(ssrc);
       
   228 		return p;
       
   229 	}
       
   230 
       
   231 	/**
       
   232 	 * Iterator for all the unicast receivers.
       
   233 	 * 
       
   234 	 * This one is used by both RTP for sending packets, as well as RTCP.
       
   235 	 * 
       
   236 	 * @return iterator for unicast participants
       
   237 	 */
       
   238 	protected Iterator<Participant> getUnicastReceivers() {
       
   239 		if (!this.rtpSession.mcSession) {
       
   240 			return this.receivers.iterator();
       
   241 		} else {
       
   242 			System.out
       
   243 					.println("Request for ParticipantDatabase.getUnicastReceivers in multicast session");
       
   244 			return null;
       
   245 		}
       
   246 	}
       
   247 
       
   248 	/**
       
   249 	 * Enumeration of all the participants with known ssrcs.
       
   250 	 * 
       
   251 	 * This is primarily used for sending packets in multicast sessions.
       
   252 	 * 
       
   253 	 * @return enumerator with all the participants with known SSRCs
       
   254 	 */
       
   255 	protected Enumeration<Participant> getParticipants() {
       
   256 		return this.ssrcTable.elements();
       
   257 	}
       
   258 
       
   259 	protected void debugPrint() {
       
   260 		System.out.println("   ParticipantDatabase.debugPrint()");
       
   261 		Participant p;
       
   262 		Enumeration enu = ssrcTable.elements();
       
   263 		while (enu.hasMoreElements()) {
       
   264 			p = (Participant) enu.nextElement();
       
   265 			System.out.println("           ssrcTable ssrc:" + p.ssrc
       
   266 					+ " cname:" + p.cname + " loc:" + p.loc + " rtpAddress:"
       
   267 					+ p.rtpAddress + " rtcpAddress:" + p.rtcpAddress);
       
   268 		}
       
   269 
       
   270 		Iterator<Participant> iter = receivers.iterator();
       
   271 		while (iter.hasNext()) {
       
   272 			p = iter.next();
       
   273 			System.out.println("           receivers: "
       
   274 					+ p.rtpAddress.toString());
       
   275 		}
       
   276 	}
       
   277 }