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