|
INET Framework for OMNeT++/OMNEST
|
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 }