RTCP.cc

Go to the documentation of this file.
00001 /***************************************************************************
00002                        RTCP.cc  -  description
00003                              -------------------
00004     (C) 2007 Ahmed Ayadi  <ahmed.ayadi@sophia.inria.fr>
00005     (C) 2001 Matthias Oppitz <Matthias.Oppitz@gmx.de>
00006 
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00023 #include "IPAddress.h"
00024 #include "UDPSocket.h"
00025 #include "UDPControlInfo_m.h"
00026 
00027 #include "RTCP.h"
00028 #include "RTPInnerPacket.h"
00029 #include "RTPParticipantInfo.h"
00030 #include "RTPSenderInfo.h"
00031 #include "RTPReceiverInfo.h"
00032 
00033 Define_Module(RTCP);
00034 
00035 RTCP::RTCP()
00036 {
00037     _participantInfos = NULL;
00038 }
00039 
00040 void RTCP::initialize()
00041 {
00042 
00043     // initialize variables
00044     _ssrcChosen = false;
00045     _leaveSession = false;
00046     _socketFdIn = -1;
00047     _socketFdOut = -1;
00048 
00049     _packetsCalculated = 0;
00050     _averagePacketSize = 0.0;
00051 
00052     _participantInfos = new cArray("ParticipantInfos");
00053 }
00054 
00055 RTCP::~RTCP()
00056 {
00057     delete _participantInfos;
00058 }
00059 
00060 void RTCP::handleMessage(cMessage *msg)
00061 {
00062 
00063     // first distinguish incoming messages by arrival gate
00064     if (msg->getArrivalGateId() == findGate("rtpIn")) {
00065         handleMessageFromRTP(msg);
00066     }
00067     else if (msg->getArrivalGateId() == findGate("udpIn")) {
00068         handleMessageFromUDP(msg);
00069     }
00070     else {
00071         handleSelfMessage(msg);
00072     }
00073 
00074     delete msg;
00075 }
00076 
00077 //
00078 // handle messages from different gates
00079 //
00080 
00081 void RTCP::handleMessageFromRTP(cMessage *msg)
00082 {
00083 
00084     // from the rtp module all messages are of type RTPInnerPacket
00085     RTPInnerPacket *rinp = check_and_cast<RTPInnerPacket *>(msg);
00086 
00087     // distinguish by type
00088     if (rinp->getType() == RTPInnerPacket::RTP_INP_INITIALIZE_RTCP) {
00089         initializeRTCP(rinp);
00090     }
00091     else if (rinp->getType() == RTPInnerPacket::RTP_INP_SENDER_MODULE_INITIALIZED) {
00092         senderModuleInitialized(rinp);
00093     }
00094     else if (rinp->getType() == RTPInnerPacket::RTP_INP_DATA_OUT) {
00095         dataOut(rinp);
00096     }
00097     else if (rinp->getType() == RTPInnerPacket::RTP_INP_DATA_IN) {
00098         dataIn(rinp);
00099     }
00100     else if (rinp->getType() == RTPInnerPacket::RTP_INP_LEAVE_SESSION) {
00101         leaveSession(rinp);
00102     }
00103     else {
00104         error("unknown RTPInnerPacket type");
00105     }
00106 }
00107 
00108 
00109 void RTCP::handleMessageFromUDP(cMessage *msg)
00110 {
00111     // from SocketLayer all message are of type cMessage
00112     readRet(PK(msg));
00113 }
00114 
00115 
00116 void RTCP::handleSelfMessage(cMessage *msg)
00117 {
00118     // it's time to create an rtcp packet
00119     if (!_ssrcChosen) {
00120         chooseSSRC();
00121         RTPInnerPacket *rinp1 = new RTPInnerPacket("rtcpInitialized()");
00122         rinp1->rtcpInitialized(_senderInfo->getSSRC());
00123         send(rinp1, "rtpOut");
00124     }
00125 
00126     createPacket();
00127 
00128     if (!_leaveSession) {
00129         scheduleInterval();
00130     }
00131 }
00132 
00133 //
00134 // methods for different messages
00135 //
00136 
00137 void RTCP::initializeRTCP(RTPInnerPacket *rinp)
00138 {
00139     _mtu = rinp->getMTU();
00140     _bandwidth = rinp->getBandwidth();
00141     _rtcpPercentage = rinp->getRtcpPercentage();
00142     _destinationAddress = rinp->getAddress();
00143     _port = rinp->getPort();
00144 
00145     _senderInfo = new RTPSenderInfo();
00146 
00147     SDESItem *sdesItem = new SDESItem(SDESItem::SDES_CNAME, rinp->getCommonName());
00148     _senderInfo->addSDESItem(sdesItem);
00149 
00150 
00151     // create server socket for receiving rtcp packets
00152     createSocket();
00153 }
00154 
00155 
00156 void RTCP::senderModuleInitialized(RTPInnerPacket *rinp)
00157 {
00158     _senderInfo->setStartTime(simTime());
00159     _senderInfo->setClockRate(rinp->getClockRate());
00160     _senderInfo->setTimeStampBase(rinp->getTimeStampBase());
00161     _senderInfo->setSequenceNumberBase(rinp->getSequenceNumberBase());
00162 }
00163 
00164 
00165 void RTCP::dataOut(RTPInnerPacket *packet)
00166 {
00167     RTPPacket *rtpPacket = check_and_cast<RTPPacket *>(packet->decapsulate());
00168     processOutgoingRTPPacket(rtpPacket);
00169 }
00170 
00171 
00172 void RTCP::dataIn(RTPInnerPacket *rinp)
00173 {
00174     RTPPacket *rtpPacket = check_and_cast<RTPPacket *>(rinp->decapsulate());
00175     //rtpPacket->dump();
00176     processIncomingRTPPacket(rtpPacket, rinp->getAddress(), rinp->getPort());
00177 }
00178 
00179 
00180 void RTCP::leaveSession(RTPInnerPacket *rinp)
00181 {
00182     _leaveSession = true;
00183 }
00184 
00185 
00186 void RTCP::connectRet()
00187 {
00188     // schedule first rtcp packet
00189     double intervalLength = 2.5 * (dblrand() + 0.5);
00190     cMessage *reminderMessage = new cMessage("Interval");
00191     scheduleAt(simTime() + intervalLength, reminderMessage);
00192 }
00193 
00194 
00195 void RTCP::readRet(cPacket *sifpIn)
00196 {
00197     RTCPCompoundPacket *packet = (RTCPCompoundPacket *)(sifpIn->decapsulate());
00198     processIncomingRTCPPacket(packet, IPAddress(_destinationAddress), _port);
00199 }
00200 
00201 void RTCP::createSocket()
00202 {
00203     // TODO UDPAppBase should be ported to use UDPSocket sometime, but for now
00204     // we just manage the UDP socket by hand...
00205     if (_socketFdIn == -1) {
00206         _socketFdIn = UDPSocket::generateSocketId();
00207         UDPControlInfo *ctrl = new UDPControlInfo();
00208         IPAddress ipaddr(_destinationAddress);
00209 
00210         if (ipaddr.isMulticast()) {
00211             ctrl->setSrcAddr(IPAddress(_destinationAddress));
00212             ctrl->setSrcPort(_port);
00213         }
00214         else {
00215              ctrl->setSrcPort(_port);
00216              ctrl->setSockId(_socketFdOut);
00217         }
00218         ctrl->setSockId((int)_socketFdIn);
00219         cMessage *msg = new cMessage("UDP_C_BIND", UDP_C_BIND);
00220         msg->setControlInfo(ctrl);
00221         send(msg,"udpOut");
00222 
00223         connectRet();
00224     }
00225 }
00226 
00227 
00228 void RTCP::scheduleInterval(){
00229 
00230     simtime_t intervalLength = _averagePacketSize * (simtime_t)(_participantInfos->size()) / (simtime_t)(_bandwidth * _rtcpPercentage * (_senderInfo->isSender() ? 1.0 : 0.75) / 100.0);
00231 
00232     // interval length must be at least 5 seconds
00233     if (intervalLength < 5.0)
00234         intervalLength = 5.0;
00235 
00236     // to avoid rtcp packet bursts multiply calculated interval length
00237     // with a random number between 0.5 and 1.5
00238     intervalLength = intervalLength * (0.5 + dblrand());
00239 
00240     intervalLength /= (double) (2.71828-1.5); // [RFC 3550] , by Ahmed ayadi
00241 
00242     cMessage *reminderMessage = new cMessage("Interval");
00243     scheduleAt(simTime() + intervalLength, reminderMessage);
00244 }
00245 
00246 
00247 void RTCP::chooseSSRC(){
00248 
00249     uint32 ssrc = 0;
00250     bool ssrcConflict = false;
00251     do {
00252         ssrc = intrand(0x7fffffff);
00253         ssrcConflict = findParticipantInfo(ssrc) != NULL;
00254     } while (ssrcConflict);
00255     ev << "chooseSSRC" << ssrc;
00256     _senderInfo->setSSRC(ssrc);
00257     _participantInfos->add(_senderInfo);
00258     _ssrcChosen = true;
00259 }
00260 
00261 
00262 void RTCP::createPacket()
00263 {
00264     // first packet in an rtcp compound packet must
00265     // be a sender or receiver report
00266     RTCPReceiverReportPacket *reportPacket;
00267 
00268     // if this rtcp end system is a sender (see SenderInformation::isSender() for
00269     // details) insert a sender report
00270     if (_senderInfo->isSender()) {
00271         RTCPSenderReportPacket *senderReportPacket = new RTCPSenderReportPacket("SenderReportPacket");
00272         senderReportPacket->setSenderReport(_senderInfo->senderReport(simTime()));
00273         reportPacket = senderReportPacket;
00274     }
00275     else
00276         reportPacket = new RTCPReceiverReportPacket("ReceiverReportPacket");
00277     reportPacket->setSSRC(_senderInfo->getSSRC());
00278 
00279 
00280     // insert receiver reports for packets from other sources
00281     for (int i = 0; i < _participantInfos->size(); i++) {
00282 
00283         if (_participantInfos->exist(i)) {
00284             RTPParticipantInfo *participantInfo = (RTPParticipantInfo *)(_participantInfos->get(i));
00285             if (participantInfo->getSSRC() != _senderInfo->getSSRC()) {
00286                 ReceptionReport *report = ((RTPReceiverInfo *)participantInfo)->receptionReport(simTime());
00287                 if (report != NULL) {
00288                     reportPacket->addReceptionReport(report);
00289                 }
00290             }
00291             participantInfo->nextInterval(simTime());
00292 
00293             if (participantInfo->toBeDeleted(simTime())) {
00294                 _participantInfos->remove(participantInfo);
00295                 delete participantInfo;
00296                 // perhaps inform the profile
00297             }
00298         }
00299     }
00300     // insert source description items (at least common name)
00301     RTCPSDESPacket *sdesPacket = new RTCPSDESPacket("SDESPacket");
00302 
00303     SDESChunk *chunk = _senderInfo->getSDESChunk();
00304     sdesPacket->addSDESChunk(chunk);
00305 
00306     RTCPCompoundPacket *compoundPacket = new RTCPCompoundPacket("RTCPCompoundPacket");
00307 
00308     compoundPacket->addRTCPPacket(reportPacket);
00309     compoundPacket->addRTCPPacket(sdesPacket);
00310 
00311     // create rtcp app/bye packets if needed
00312     if (_leaveSession) {
00313         RTCPByePacket *byePacket = new RTCPByePacket("ByePacket");
00314         byePacket->setSSRC(_senderInfo->getSSRC());
00315         compoundPacket->addRTCPPacket(byePacket);
00316     }
00317 
00318     calculateAveragePacketSize(compoundPacket->getByteLength());
00319 
00320     cPacket *msg = new cPacket("RTCPCompoundPacket");
00321     msg->encapsulate(compoundPacket);
00322     msg->setKind(UDP_C_DATA);
00323     UDPControlInfo *ctrl = new UDPControlInfo();
00324     ctrl->setSockId(_socketFdOut);
00325     ctrl->setDestAddr(_destinationAddress);
00326     ctrl->setDestPort(_port);
00327     msg->setControlInfo(ctrl);
00328 
00329     send(msg, "udpOut");
00330 
00331     if (_leaveSession) {
00332         RTPInnerPacket *rinp = new RTPInnerPacket("sessionLeft()");
00333         rinp->sessionLeft();
00334         send(rinp, "rtpOut");
00335     }
00336 }
00337 
00338 
00339 void RTCP::processOutgoingRTPPacket(RTPPacket *packet)
00340 {
00341     _senderInfo->processRTPPacket(packet, getId(), simTime());
00342 }
00343 
00344 
00345 void RTCP::processIncomingRTPPacket(RTPPacket *packet, IPAddress address, int port)
00346 {
00347     uint32 ssrc = packet->getSSRC();
00348     RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
00349     if (participantInfo == NULL) {
00350         participantInfo = new RTPParticipantInfo(ssrc);
00351         participantInfo->setAddress(address);
00352         participantInfo->setRTPPort(port);
00353         _participantInfos->add(participantInfo);
00354     }
00355     else {
00356         // check for ssrc conflict
00357         if (participantInfo->getAddress() != address) {
00358             // we have an address conflict
00359         }
00360         if (participantInfo->getRTPPort() == PORT_UNDEF) {
00361             participantInfo->setRTPPort(port);
00362         }
00363         else if (participantInfo->getRTPPort() != port) {
00364             // we have an rtp port conflict
00365         }
00366     }
00367     participantInfo->processRTPPacket(packet, getId(),  packet->getArrivalTime());
00368 }
00369 
00370 
00371 void RTCP::processIncomingRTCPPacket(RTCPCompoundPacket *packet, IPAddress address, int port)
00372 {
00373     calculateAveragePacketSize(packet->getByteLength());
00374     cArray *rtcpPackets = packet->getRtcpPackets();
00375 
00376     simtime_t arrivalTime = packet->getArrivalTime();
00377     delete packet;
00378 
00379    for (int i = 0; i < rtcpPackets->size(); i++) {
00380         if (rtcpPackets->exist(i)) {
00381             // remove the rtcp packet from the rtcp compound packet
00382             RTCPPacket *rtcpPacket = (RTCPPacket *)(rtcpPackets->remove(i));
00383             if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_SR) {
00384                 RTCPSenderReportPacket *rtcpSenderReportPacket = (RTCPSenderReportPacket *)rtcpPacket;
00385                 uint32 ssrc = rtcpSenderReportPacket->getSSRC();
00386                 RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
00387 
00388                 if (participantInfo == NULL) {
00389                     participantInfo = new RTPReceiverInfo(ssrc);
00390                     participantInfo->setAddress(address);
00391                     participantInfo->setRTCPPort(port);
00392                     _participantInfos->add(participantInfo);
00393                 }
00394                 else {
00395                     if (participantInfo->getAddress() == address) {
00396                         if (participantInfo->getRTCPPort() == PORT_UNDEF) {
00397                             participantInfo->setRTCPPort(port);
00398                         }
00399                         else {
00400                             // check for ssrc conflict
00401                         }
00402                     }
00403                     else {
00404                         // check for ssrc conflict
00405                     }
00406                 }
00407                 participantInfo->processSenderReport(rtcpSenderReportPacket->getSenderReport(), simTime());
00408 
00409                 cArray *receptionReports = rtcpSenderReportPacket->getReceptionReports();
00410                 for (int j = 0; j < receptionReports->size(); j++) {
00411                     if (receptionReports->exist(j)) {
00412                         ReceptionReport *receptionReport = (ReceptionReport *)(receptionReports->remove(j));
00413                         if (_senderInfo) {
00414                             if (receptionReport->getSSRC() == _senderInfo->getSSRC()) {
00415                                 _senderInfo->processReceptionReport(receptionReport, simTime());
00416                             }
00417                         }
00418                         else
00419                             //cancelAndDelete(receptionReport);
00420                             delete receptionReport;
00421                     }
00422                 }
00423                 delete receptionReports;
00424 
00425             }
00426             else if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_RR) {
00427                 RTCPReceiverReportPacket *rtcpReceiverReportPacket = (RTCPReceiverReportPacket *)rtcpPacket;
00428                 uint32 ssrc = rtcpReceiverReportPacket->getSSRC();
00429                 RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
00430                 if (participantInfo == NULL) {
00431                     participantInfo = new RTPReceiverInfo(ssrc);
00432                     participantInfo->setAddress(address);
00433                     participantInfo->setRTCPPort(port);
00434                     _participantInfos->add(participantInfo);
00435                 }
00436                 else {
00437                     if (participantInfo->getAddress() == address) {
00438                         if (participantInfo->getRTCPPort() == PORT_UNDEF) {
00439                             participantInfo->setRTCPPort(port);
00440                         }
00441                         else {
00442                             // check for ssrc conflict
00443                         }
00444                     }
00445                     else {
00446                         // check for ssrc conflict
00447                     }
00448                 }
00449 
00450                 cArray *receptionReports = rtcpReceiverReportPacket->getReceptionReports();
00451                 for (int j = 0; j < receptionReports->size(); j++) {
00452                     if (receptionReports->exist(j)) {
00453                         ReceptionReport *receptionReport = (ReceptionReport *)(receptionReports->remove(j));
00454                         if (_senderInfo) {
00455 
00456                             if (receptionReport->getSSRC() == _senderInfo->getSSRC()) {
00457                                 _senderInfo->processReceptionReport(receptionReport, simTime());
00458                             }
00459                         }
00460 
00461                          else
00462                             //cancelAndDelete(receptionReport);
00463                              delete receptionReport;
00464                     }
00465                 }
00466                 delete receptionReports;
00467             }
00468             else if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_SDES) {
00469                 RTCPSDESPacket *rtcpSDESPacket = (RTCPSDESPacket *)rtcpPacket;
00470                 cArray *sdesChunks = rtcpSDESPacket->getSdesChunks();
00471 
00472                 for (int j = 0; j < sdesChunks->size(); j++) {
00473                     if (sdesChunks->exist(j)) {
00474                         // remove the sdes chunk from the cArray of sdes chunks
00475                         SDESChunk *sdesChunk = (SDESChunk *)(sdesChunks->remove(j));
00476                         // this is needed to avoid seg faults
00477                         //sdesChunk->setOwner(this);
00478                         uint32 ssrc = sdesChunk->getSSRC();
00479                         RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
00480                         if (participantInfo == NULL) {
00481                             participantInfo = new RTPReceiverInfo(ssrc);
00482                             participantInfo->setAddress(address);
00483                             participantInfo->setRTCPPort(port);
00484                             _participantInfos->add(participantInfo);
00485                         }
00486                         else {
00487                             // check for ssrc conflict
00488                         }
00489                         participantInfo->processSDESChunk(sdesChunk, arrivalTime);
00490                     }
00491                 }
00492                 delete sdesChunks;
00493 
00494             }
00495             else if (rtcpPacket->getPacketType() == RTCPPacket::RTCP_PT_BYE) {
00496                 RTCPByePacket *rtcpByePacket = (RTCPByePacket *)rtcpPacket;
00497                 uint32 ssrc = rtcpByePacket->getSSRC();
00498                 RTPParticipantInfo *participantInfo = findParticipantInfo(ssrc);
00499 
00500                 if (participantInfo != NULL && participantInfo != _senderInfo) {
00501                     _participantInfos->remove(participantInfo);
00502 
00503                     delete participantInfo;
00504                     // perhaps it would be useful to inform
00505                     // the profile to remove the corresponding
00506                     // receiver module
00507                 }
00508             }
00509             else {
00510                 // app rtcp packets
00511             }
00512         delete rtcpPacket;
00513         }
00514     }
00515     delete rtcpPackets;
00516 }
00517 
00518 
00519 RTPParticipantInfo *RTCP::findParticipantInfo(uint32 ssrc)
00520 {
00521     char *ssrcString = RTPParticipantInfo::ssrcToName(ssrc);
00522     int participantIndex = _participantInfos->find(ssrcString);
00523     if (participantIndex != -1) {
00524         return (RTPParticipantInfo *)(_participantInfos->get(participantIndex));
00525     }
00526     else {
00527         return NULL;
00528     }
00529 }
00530 
00531 
00532 void RTCP::calculateAveragePacketSize(int size)
00533 {
00534     // add size of ip and udp header to given size before calculating
00535     _averagePacketSize = ((double)(_packetsCalculated) * _averagePacketSize + (double)(size + 20 + 8)) / (double)(++_packetsCalculated);
00536 }