diff -r 537ddd8aa407 -r 2036ebfaccda src/jlibrtp/ParticipantDatabase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jlibrtp/ParticipantDatabase.java Fri Nov 20 19:29:42 2009 +0100 @@ -0,0 +1,277 @@ +/** + * Java RTP Library (jlibrtp) + * Copyright (C) 2006 Arne Kepp + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package jlibrtp; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.concurrent.ConcurrentHashMap; + +/** + * The participant database maintains three hashtables with participants. + * + * The key issue is to be fast for operations that happen every time an RTP + * packet is sent or received. We allow linear searching in cases where we need + * to update participants with information. + * + * The keying is therefore usually the SSRC. In cases where we have the cname, + * but no SSRC is known (no SDES packet has been received), a simple hash i + * calculated based on the CNAME. The RTCP code should, when receiving SDES + * packets, check whether the participant is known and update the copy in this + * database with SSRC if needed. + * + * @author Arne Kepp + */ +public class ParticipantDatabase { + /** The parent RTP Session */ + RTPSession rtpSession = null; + /** + * A linked list to hold participants explicitly added by the application In + * unicast mode this is the list used for RTP and RTCP transmission, in + * multicast it should not be in use. + */ + LinkedList receivers = new LinkedList(); + /** + * The hashtable holds participants added through received RTP and RTCP + * packets, as well as participants that have been linked to an SSRC by ip + * address (in unicast mode). + */ + ConcurrentHashMap ssrcTable = new ConcurrentHashMap(); + + /** + * Simple constructor + * + * @param parent + * parent RTPSession + */ + protected ParticipantDatabase(RTPSession parent) { + rtpSession = parent; + } + + /** + * + * @param cameFrom + * 0: Application, 1: RTP packet, 2: RTCP + * @param p + * the participant + * @return 0 if okay, -1 if not + */ + protected int addParticipant(int cameFrom, Participant p) { + // Multicast or not? + if (this.rtpSession.mcSession) { + return this.addParticipantMulticast(cameFrom, p); + } else { + return this.addParticipantUnicast(cameFrom, p); + } + + } + + /** + * Add a multicast participant to the database + * + * @param cameFrom + * 0: Application, 1,2: discovered through RTP or RTCP + * @param p + * the participant to add + * @return 0 if okay, -2 if redundant, -1 if adding participant to multicast + */ + private int addParticipantMulticast(int cameFrom, Participant p) { + if (cameFrom == 0) { + System.out + .println("ParticipantDatabase.addParticipant() doesnt expect" + + " application to add participants to multicast session."); + return -1; + } else { + // Check this one is not redundant + if (this.ssrcTable.contains(p.ssrc)) { + System.out.println("ParticipantDatabase.addParticipant() SSRC " + + "already known " + Long.toString(p.ssrc)); + return -2; + } else { + this.ssrcTable.put(p.ssrc, p); + return 0; + } + } + } + + /** + * Add a unicast participant to the database + * + * Result will be reported back through tpSession.appIntf.userEvent + * + * @param cameFrom + * 0: Application, 1,2: discovered through RTP or RTCP + * @param p + * the participant to add + * @return 0 if new, 1 if + */ + private int addParticipantUnicast(int cameFrom, Participant p) { + if (cameFrom == 0) { + // Check whether there is a match in the ssrcTable + boolean notDone = true; + + Enumeration enu = this.ssrcTable.elements(); + while (notDone && enu.hasMoreElements()) { + Participant part = enu.nextElement(); + if (part.unexpected + && (part.rtcpReceivedFromAddress + .equals(part.rtcpAddress.getAddress()) || part.rtpReceivedFromAddress + .equals(part.rtpAddress.getAddress()))) { + + part.rtpAddress = p.rtpAddress; + part.rtcpAddress = p.rtcpAddress; + part.unexpected = false; + + // Report the match back to the application + Participant[] partArray = { part }; + this.rtpSession.appIntf.userEvent(5, partArray); + + notDone = false; + p = part; + } + } + + // Add to the table of people that we send packets to + this.receivers.add(p); + return 0; + + } else { + // Check whether there's a match in the receivers table + boolean notDone = true; + // System.out.println("GOT " + p.cname); + Iterator iter = this.receivers.iterator(); + + while (notDone && iter.hasNext()) { + Participant part = iter.next(); + + // System.out.println(part.rtpAddress.getAddress().toString() + // + " " + part.rtcpAddress.getAddress().toString() + // + " " + p.rtpReceivedFromAddress.getAddress().toString() + // + " " + p.rtcpReceivedFromAddress.getAddress().toString()); + + // System.out.println(" HUUHHHH? " + + // p.rtcpReceivedFromAddress.getAddress().equals(part.rtcpAddress.getAddress())); + if ((cameFrom == 1 && p.rtpReceivedFromAddress.getAddress() + .equals(part.rtpAddress.getAddress())) + || (cameFrom == 2 && p.rtcpReceivedFromAddress + .getAddress().equals( + part.rtcpAddress.getAddress()))) { + + part.rtpReceivedFromAddress = p.rtpReceivedFromAddress; + part.rtcpReceivedFromAddress = p.rtcpReceivedFromAddress; + + // Move information + part.ssrc = p.ssrc; + part.cname = p.cname; + part.name = p.name; + part.loc = p.loc; + part.phone = p.phone; + part.email = p.email; + part.note = p.note; + part.tool = p.tool; + part.priv = p.priv; + + this.ssrcTable.put(part.ssrc, part); + + // Report the match back to the application + Participant[] partArray = { part }; + this.rtpSession.appIntf.userEvent(5, partArray); + return 0; + } + } + + // No match? ok + this.ssrcTable.put(p.ssrc, p); + return 0; + } + } + + /** + * Remove a participant from all tables + * + * @param p + * the participant to be removed + */ + protected void removeParticipant(Participant p) { + if (!this.rtpSession.mcSession) + this.receivers.remove(p); + + this.ssrcTable.remove(p.ssrc, p); + } + + /** + * Find a participant based on the ssrc + * + * @param ssrc + * of the participant to be found + * @return the participant, null if unknonw + */ + protected Participant getParticipant(long ssrc) { + Participant p = null; + p = ssrcTable.get(ssrc); + return p; + } + + /** + * Iterator for all the unicast receivers. + * + * This one is used by both RTP for sending packets, as well as RTCP. + * + * @return iterator for unicast participants + */ + protected Iterator getUnicastReceivers() { + if (!this.rtpSession.mcSession) { + return this.receivers.iterator(); + } else { + System.out + .println("Request for ParticipantDatabase.getUnicastReceivers in multicast session"); + return null; + } + } + + /** + * Enumeration of all the participants with known ssrcs. + * + * This is primarily used for sending packets in multicast sessions. + * + * @return enumerator with all the participants with known SSRCs + */ + protected Enumeration getParticipants() { + return this.ssrcTable.elements(); + } + + protected void debugPrint() { + System.out.println(" ParticipantDatabase.debugPrint()"); + Participant p; + Enumeration enu = ssrcTable.elements(); + while (enu.hasMoreElements()) { + p = (Participant) enu.nextElement(); + System.out.println(" ssrcTable ssrc:" + p.ssrc + + " cname:" + p.cname + " loc:" + p.loc + " rtpAddress:" + + p.rtpAddress + " rtcpAddress:" + p.rtcpAddress); + } + + Iterator iter = receivers.iterator(); + while (iter.hasNext()) { + p = iter.next(); + System.out.println(" receivers: " + + p.rtpAddress.toString()); + } + } +}