blob: 4be6a4545205183a9e0e78c580482ec2fa3823e5 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// ccRTP. If you copy code from other releases into a copy of GNU
29// ccRTP, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU ccRTP, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39/**
40 * @file control.cpp
41 *
42 * @short QueueRTCPManager classes implementation.
43 **/
44
45#include "private.h"
46#include <cstdlib>
47#include <ccrtp/cqueue.h>
48#include <cstdlib>
49#include <climits>
50
51#ifdef CCXX_NAMESPACES
52namespace ost {
53#endif
54
55const uint16 QueueRTCPManager::TIMEOUT_MULTIPLIER = 5;
56const double QueueRTCPManager::RECONSIDERATION_COMPENSATION = 2.718281828 - 1.5;
57const SDESItemType QueueRTCPManager::firstSchedulable = SDESItemTypeNAME;
58const SDESItemType QueueRTCPManager::lastSchedulable = SDESItemTypePRIV;
59/// maximum end to end delay: unlimited
60const microtimeout_t QueueRTCPManager::defaultEnd2EndDelay = 0;
61
62QueueRTCPManager::QueueRTCPManager(uint32 size, RTPApplication& app):
63RTPDataQueue(size), RTCPCompoundHandler(RTCPCompoundHandler::defaultPathMTU),
64queueApplication(app)
65{
66 controlServiceActive = false;
67 controlBwFract = 0.05f;
68 sendControlBwFract = 0.25;
69 recvControlBwFract = 1-sendControlBwFract;
70 ctrlSendCount = 0;
71
72 lowerHeadersSize = networkHeaderSize() + transportHeaderSize();
73
74 nextScheduledSDESItem = SDESItemTypeNAME;
75
76 // initialize RTCP timing
77 reconsInfo.rtcpTp.tv_sec = reconsInfo.rtcpTc.tv_sec =
78 reconsInfo.rtcpTn.tv_sec = 0;
79 reconsInfo.rtcpTp.tv_usec = reconsInfo.rtcpTc.tv_usec =
80 reconsInfo.rtcpTn.tv_usec = 0;
81 reconsInfo.rtcpPMembers = 1;
82
83 rtcpWeSent = false;
84 rtcpAvgSize = sizeof(RTCPFixedHeader) + sizeof(uint32) +
85 sizeof(SenderInfo);
86 rtcpInitial = true;
87 // force an initial check for incoming RTCP packets
88 gettimeofday(&rtcpNextCheck,NULL);
89 // check for incoming RTCP packets every 1/4 seconds.
90 rtcpCheckInterval.tv_sec = 0;
91 rtcpCheckInterval.tv_usec = 250000;
92 timersub(&rtcpNextCheck,&rtcpCheckInterval,&rtcpLastCheck);
93
94 lastSendPacketCount = 0;
95
96 rtcpMinInterval = 5000000; // 5 seconds.
97
98 leavingDelay = 1000000; // 1 second
99 end2EndDelay = getDefaultEnd2EndDelay();
100
101 // Fill in fixed fields that will never change
102 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer);
103 pkt->fh.version = CCRTP_VERSION;
104 // (SSRCCollision will have to take this into account)
105 pkt->info.SR.ssrc = getLocalSSRCNetwork();
106
107 // allow to start RTCP service once everything is set up
108 controlServiceActive = true;
109}
110
111// TODO Streamline this code (same as above, put into a separate method)
112QueueRTCPManager::QueueRTCPManager(uint32 ssrc, uint32 size, RTPApplication& app):
113RTPDataQueue(&ssrc, size),
114RTCPCompoundHandler(RTCPCompoundHandler::defaultPathMTU),
115queueApplication(app)
116{
117 controlServiceActive = false;
118 controlBwFract = 0.05f;
119 sendControlBwFract = 0.25;
120 recvControlBwFract = 1-sendControlBwFract;
121 ctrlSendCount = 0;
122
123 lowerHeadersSize = networkHeaderSize() + transportHeaderSize();
124
125 nextScheduledSDESItem = SDESItemTypeNAME;
126
127 // initialize RTCP timing
128 reconsInfo.rtcpTp.tv_sec = reconsInfo.rtcpTc.tv_sec =
129 reconsInfo.rtcpTn.tv_sec = 0;
130
131 reconsInfo.rtcpTp.tv_usec = reconsInfo.rtcpTc.tv_usec =
132 reconsInfo.rtcpTn.tv_usec = 0;
133
134 reconsInfo.rtcpPMembers = 1;
135
136 rtcpWeSent = false;
137 rtcpAvgSize = sizeof(RTCPFixedHeader) + sizeof(uint32) + sizeof(SenderInfo);
138 rtcpInitial = true;
139 // force an initial check for incoming RTCP packets
140 gettimeofday(&rtcpNextCheck,NULL);
141 // check for incoming RTCP packets every 1/4 seconds.
142 rtcpCheckInterval.tv_sec = 0;
143 rtcpCheckInterval.tv_usec = 250000;
144 timersub(&rtcpNextCheck,&rtcpCheckInterval,&rtcpLastCheck);
145
146 lastSendPacketCount = 0;
147
148 rtcpMinInterval = 5000000; // 5 seconds.
149
150 leavingDelay = 1000000; // 1 second
151 end2EndDelay = getDefaultEnd2EndDelay();
152
153 // Fill in fixed fields that will never change
154 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer);
155 pkt->fh.version = CCRTP_VERSION;
156 // (SSRCCollision will have to take this into account)
157 pkt->info.SR.ssrc = getLocalSSRCNetwork();
158
159 // allow to start RTCP service once everything is set up
160 controlServiceActive = true;
161}
162
163QueueRTCPManager::~QueueRTCPManager()
164{
165 endQueueRTCPManager();
166}
167
168void QueueRTCPManager::endQueueRTCPManager()
169{
170 controlServiceActive = false;
171 controlBwFract = sendControlBwFract = 0;
172}
173
174bool QueueRTCPManager::checkSSRCInRTCPPkt(SyncSourceLink& sourceLink,
175bool is_new, InetAddress& network_address, tpport_t transport_port)
176{
177 bool result = true;
178
179 // Test if the source is new and it is not the local one.
180 if ( is_new && sourceLink.getSource()->getID() != getLocalSSRC() )
181 return result;
182
183 SyncSource *s = sourceLink.getSource();
184 if ( s->getControlTransportPort() != transport_port ||
185 s->getNetworkAddress() != network_address ) {
186 // SSRC collision or a loop has happened
187 if ( s->getID() != getLocalSSRC() ) {
188 // TODO: Optional error counter.
189
190 // Note this differs from the default in the RFC.
191 // Discard packet only when the collision is
192 // repeating (to avoid flip-flopping)
193 if ( sourceLink.getPrevConflict() &&
194 (
195 (network_address ==
196 sourceLink.getPrevConflict()->networkAddress)
197 &&
198 (transport_port ==
199 sourceLink.getPrevConflict()->controlTransportPort)
200 ) ) {
201 // discard packet and do not flip-flop
202 result = false;
203 } else {
204 // Record who has collided so that in
205 // the future we can how if the
206 // collision repeats.
207 sourceLink.setPrevConflict(network_address,
208 0,transport_port);
209 // Change sync source transport address
210 setControlTransportPort(*s,transport_port);
211 setNetworkAddress(*s,network_address);
212 }
213
214 } else {
215 // Collision or loop of own packets.
216 ConflictingTransportAddress* conflicting =
217 searchControlConflict(network_address,
218 transport_port);
219 if ( conflicting ) {
220 // Optional error counter.
221 updateConflict(*conflicting);
222 result = false;
223 } else {
224 // New collision
225 addConflict(s->getNetworkAddress(),
226 s->getDataTransportPort(),
227 s->getControlTransportPort());
228 dispatchBYE("SSRC collision detected when receiving RTCP packet");
229 renewLocalSSRC();
230 setNetworkAddress(*s,network_address);
231 setControlTransportPort(*s,transport_port);
232 setControlTransportPort(*s,0);
233 sourceLink.initStats();
234 }
235 }
236 }
237 return result;
238}
239
240void QueueRTCPManager::controlReceptionService()
241{
242 if ( !controlServiceActive )
243 return;
244
245 // A) see if there are incoming RTCP packets
246 gettimeofday(&(reconsInfo.rtcpTc),NULL);
247 if ( timercmp(&(reconsInfo.rtcpTc),&rtcpNextCheck,>=) ) {
248 while ( isPendingControl(0) )
249 takeInControlPacket();
250 // If this do loops more than once, then we have not
251 // been in time. So it skips until the next future
252 // instant.
253 do {
254 timeval tmp = rtcpNextCheck;
255 timeradd(&rtcpLastCheck,&rtcpCheckInterval,
256 &rtcpNextCheck);
257 rtcpLastCheck = tmp;
258 } while ( timercmp(&(reconsInfo.rtcpTc), &(rtcpNextCheck), >=) );
259 }
260}
261
262void QueueRTCPManager::controlTransmissionService()
263{
264 if ( !controlServiceActive )
265 return;
266
267 // B) send RTCP packets
268 gettimeofday(&(reconsInfo.rtcpTc),NULL);
269 if ( timercmp(&(reconsInfo.rtcpTc),&(reconsInfo.rtcpTn),>=) ) {
270 if ( timerReconsideration() ) {
271 // this would update to last received RTCP packets
272 //while ( isPendingControl(0) )
273 // takeInControlPacket();
274 rtcpLastCheck = reconsInfo.rtcpTc;
275 dispatchControlPacket();
276 if (rtcpInitial)
277 rtcpInitial = false;
278 expireSSRCs();
279 reconsInfo.rtcpTp = reconsInfo.rtcpTc;
280 // we have updated tp and sent a report, so we
281 // have to recalculate the sending interval
282 timeval T = computeRTCPInterval();
283 timeradd(&(reconsInfo.rtcpTc),&T,&(reconsInfo.rtcpTn));
284
285 // record current number of members for the
286 // next check.
287 reconsInfo.rtcpPMembers = getMembersCount();
288 }
289 }
290}
291
292bool QueueRTCPManager::timerReconsideration()
293{
294 bool result = false;
295 // compute again the interval to confirm it under current
296 // circumstances
297 timeval T = computeRTCPInterval();
298 timeradd(&(reconsInfo.rtcpTp),&T,&(reconsInfo.rtcpTn));
299 gettimeofday(&(reconsInfo.rtcpTc),NULL);
300 if ( timercmp(&(reconsInfo.rtcpTc),&(reconsInfo.rtcpTn),>=) ) {
301 reconsInfo.rtcpTp = reconsInfo.rtcpTc;
302 result = true;
303 }
304 return result;
305}
306
307void
308QueueRTCPManager::expireSSRCs()
309{}
310
311void
312QueueRTCPManager::takeInControlPacket()
313{
314 size_t len = 0;
315 InetHostAddress network_address;
316 tpport_t transport_port;
317 len = recvControl(rtcpRecvBuffer,getPathMTU(),network_address, transport_port);
318
319 // get time of arrival
320 struct timeval recvtime;
321 gettimeofday(&recvtime,NULL);
322
323 // process a 'len' octets long RTCP compound packet
324
325 // Check validity of the header fields of the compound packet
326 if ( !RTCPCompoundHandler::checkCompoundRTCPHeader(len) )
327 return;
328
329 RTCPPacket *pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer);
330
331 // TODO: for now, we do nothing with the padding bit
332 // in the header.
333
334 bool source_created;
335 SyncSourceLink* sourceLink = getSourceBySSRC(pkt->getSSRC(),source_created);
336 SyncSource* s = sourceLink->getSource();
337
338 if ( source_created ) {
339 // Set control transport address.
340 setControlTransportPort(*s,transport_port);
341 // Network address is assumed to be the same as the control one
342 setNetworkAddress(*s,network_address);
343 sourceLink->initStats();
344 sourceLink->setProbation(getMinValidPacketSequence());
345 if ( sourceLink->getHello() )
346 onNewSyncSource(*s);
347 } else if ( s->getControlTransportPort() == 0 ) {
348 // Test if RTP data packets had been received but this
349 // is the first control packet from this source.
350 setControlTransportPort(*s,transport_port);
351 }
352 // record reception time
353 sourceLink->lastRTCPPacketTime = recvtime;
354 sourceLink->lastRTCPSRTime = recvtime;
355
356 size_t pointer = 0;
357 // Check the first packet is a report and do special
358 // processing for SR reports.
359 if ( RTCPPacket::tRR == pkt->fh.type ) {
360 // no special initialization is required for
361 // RR reports, all reports will be processed
362 // in the do-while down here.
363 } else if ( RTCPPacket::tSR == pkt->fh.type ){
364 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
365 network_address,
366 transport_port) )
367 sourceLink->lastRTCPSRTime = recvtime;
368 onGotSR(*s,pkt->info.SR,pkt->fh.block_count);
369 // Advance to the next packet in the compound.
370 pointer += pkt->getLength();
371 pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer +pointer);
372 } else if ( RTCPPacket::tXR == pkt->fh.type ) {
373 // TODO: handle XR reports.
374 } else {
375 // Ignore RTCP types unknown.
376 }
377
378 // Process all RR reports.
379 while ( (pointer < len) && (RTCPPacket::tRR == pkt->fh.type) ) {
380 sourceLink = getSourceBySSRC(pkt->getSSRC(),
381 source_created);
382 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
383 network_address,transport_port) )
384 onGotRR(*s,pkt->info.RR,pkt->fh.block_count);
385 // Advance to the next packet in the compound
386 pointer += pkt->getLength();
387 pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer +pointer);
388 }
389
390 // SDES, APP and BYE. process first everything but the
391 // BYE packets.
392 bool cname_found = false;
393 while ( (pointer < len ) &&
394 (pkt->fh.type == RTCPPacket::tSDES ||
395 pkt->fh.type == RTCPPacket::tAPP) ) {
396 I ( cname_found || !pkt->fh.padding );
397 sourceLink = getSourceBySSRC(pkt->getSSRC(),
398 source_created);
399 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
400 network_address,
401 transport_port) ) {
402 if ( pkt->fh.type == RTCPPacket::tSDES ) {
403 bool cname = onGotSDES(*s,*pkt);
404 cname_found = cname_found? cname_found : cname;
405 } else if ( pkt->fh.type == RTCPPacket::tAPP ) {
406 onGotAPP(*s,pkt->info.APP,pkt->getLength());
407 // pointer += pkt->getLength();
408 } else {
409 // error?
410 }
411 }
412 // Get the next packet in the compound.
413 pointer += pkt->getLength();
414 pkt = reinterpret_cast<RTCPPacket *>(rtcpRecvBuffer +pointer);
415 }
416
417 // TODO: error? if !cname_found
418
419 // process BYE packets
420 while ( pointer < len ) {
421 if ( pkt->fh.type == RTCPPacket::tBYE ) {
422 sourceLink = getSourceBySSRC(pkt->getSSRC(),
423 source_created);
424 if ( checkSSRCInRTCPPkt(*sourceLink,source_created,
425 network_address,
426 transport_port) )
427 getBYE(*pkt,pointer,len);
428 } else if ( pkt->fh.type != RTCPPacket::tBYE ) {
429 break; // TODO: check non-BYE out of place.
430 } else {
431 break;
432 }
433 }
434
435 // Call plug-in in case there are profile extensions
436 // at the end of the SR/RR.
437 if ( pointer != len ) {
438 onGotRRSRExtension(rtcpRecvBuffer + pointer,
439 len - pointer);
440 }
441
442 // Everything went right, update the RTCP average size
443 updateAvgRTCPSize(len);
444}
445
446bool QueueRTCPManager::end2EndDelayed(IncomingRTPPktLink& pl)
447{
448 bool result = false;
449
450 if ( 0 != getEnd2EndDelay() ) {
451 SyncSourceLink* sl = pl.getSourceLink();
452 void* si = sl->getSenderInfo();
453 if ( NULL != si ) {
454 RTCPSenderInfo rsi(si);
455 uint32 tsInc = pl.getPacket()->getTimestamp() -
456 rsi.getRTPTimestamp();
457 // approx.
458 microtimeout_t Inc = tsInc * 1000 /
459 (getCurrentRTPClockRate() / 1000);
460 timeval timevalInc = microtimeout2Timeval(Inc);
461
462 timeval tNTP = NTP2Timeval(rsi.getNTPTimestampInt(),
463 rsi.getNTPTimestampFrac());
464 timeval packetTime;
465 timeradd(&tNTP,&timevalInc,&packetTime);
466 timeval now, diff;
467 gettimeofday(&now,NULL);
468 timersub(&now,&packetTime,&diff);
469
470 if ( timeval2microtimeout(diff) > getEnd2EndDelay() )
471 result = true;
472 }
473 }
474 return result;
475}
476
477void QueueRTCPManager::onGotSR(SyncSource& source, SendReport& SR, uint8)
478{
479 // We ignore the receiver blocks and just get the sender info
480 // at the beginning of the SR.
481 getLink(source)->setSenderInfo(reinterpret_cast<unsigned char*>(&(SR.sinfo)));
482}
483
484void QueueRTCPManager::onGotRR(SyncSource& source, RecvReport& RR, uint8 blocks)
485{
486 for ( uint8 i = 0; i < blocks; i++) {
487 // this generic RTCP manager ignores reports about
488 // other sources than the local one
489 if ( getLocalSSRCNetwork() == RR.ssrc ) {
490 getLink(source)->
491 setReceiverInfo
492 (reinterpret_cast<unsigned char*>(&(RR.blocks[i].rinfo)));
493 }
494 }
495}
496
497void QueueRTCPManager::updateAvgRTCPSize(size_t len)
498{
499 size_t newlen = len;
500 newlen += lowerHeadersSize;
501 rtcpAvgSize = (uint16)(( (15 * rtcpAvgSize) >> 4 ) + ( newlen >> 4));
502}
503
504bool QueueRTCPManager::getBYE(RTCPPacket& pkt, size_t& pointer, size_t)
505{
506 if ( 0 == pkt.fh.block_count )
507 return false;
508
509 char *reason = NULL;
510
511 if ( (sizeof(RTCPFixedHeader) + pkt.fh.block_count * sizeof(uint32))
512 < pkt.getLength() ) {
513 uint16 endpointer = (uint16)(pointer + sizeof(RTCPFixedHeader) +
514 pkt.fh.block_count * sizeof(uint32));
515 uint16 len = rtcpRecvBuffer[endpointer];
516 reason = new char[len + 1];
517 memcpy(reason,rtcpRecvBuffer + endpointer + 1,len);
518 reason[len] = '\0';
519 } else { // avoid dangerous conversion of NULL to a C++ string.
520 reason = new char[1];
521 reason[0] = '\0';
522 }
523
524 int i = 0;
525 while ( i < pkt.fh.block_count ) {
526 bool created;
527 SyncSourceLink* srcLink =
528 getSourceBySSRC(pkt.getSSRC(),created);
529 i++;
530 if( srcLink->getGoodbye() )
531 onGotGoodbye(*(srcLink->getSource()),reason);
532 BYESource(pkt.getSSRC());
533 setState(*(srcLink->getSource()),SyncSource::stateLeaving);
534
535 reverseReconsideration();
536 }
537
538 delete [] reason;
539 pointer += pkt.getLength();
540 return true;
541}
542
543void QueueRTCPManager::reverseReconsideration()
544{
545 if ( getMembersCount() < reconsInfo.rtcpPMembers ) {
546 timeval inc;
547
548 // reconsider reconsInfo.rtcpTn (time for next RTCP packet)
549 microtimeout_t t =
550 (reconsInfo.rtcpTn.tv_sec - reconsInfo.rtcpTc.tv_sec) *
551 1000000 +
552 (reconsInfo.rtcpTn.tv_usec - reconsInfo.rtcpTc.tv_usec);
553 t *= getMembersCount();
554 t /= reconsInfo.rtcpPMembers;
555 inc.tv_usec = t % 1000000;
556 inc.tv_sec = t / 1000000;
557 timeradd(&(reconsInfo.rtcpTc),&inc,&(reconsInfo.rtcpTn));
558
559 // reconsider tp (time for previous RTCP packet)
560 t = (reconsInfo.rtcpTc.tv_sec - reconsInfo.rtcpTp.tv_sec) *
561 1000000 +
562 (reconsInfo.rtcpTc.tv_usec - reconsInfo.rtcpTp.tv_usec);
563 t *= getMembersCount();
564 t /= reconsInfo.rtcpPMembers;
565 inc.tv_usec = t % 1000000;
566 inc.tv_sec = t / 1000000;
567 timeradd(&(reconsInfo.rtcpTc),&inc,&(reconsInfo.rtcpTp));
568 }
569 reconsInfo.rtcpPMembers = getMembersCount();
570}
571
572bool QueueRTCPManager::onGotSDES(SyncSource& source, RTCPPacket& pkt)
573{
574 // Take into account that length fields in SDES items are
575 // 8-bit long, so no ntoh[s|l] is required
576 bool cname_found = false;
577
578 ptrdiff_t pointer = reinterpret_cast<unsigned char*>(&pkt) - rtcpRecvBuffer;
579 uint16 i = 0;
580 do {
581 size_t len = pkt.getLength();
582 pointer += sizeof(RTCPFixedHeader);
583 SDESChunk* chunk = (SDESChunk*)(rtcpRecvBuffer + pointer);
584
585 bool source_created = false;
586 // TODO: avoid searching again the source of the first chunk.
587 SyncSourceLink* sourceLink =
588 getSourceBySSRC(chunk->getSSRC(),
589 source_created);
590 // TODO: check that there are no two chunks with the
591 // same SSRC but different CNAME
592 SyncSource& src = *( sourceLink->getSource() );
593
594 if ( onGotSDESChunk(source,*chunk,len) )
595 cname_found = true;
596 pointer +=len;
597 if( sourceLink->getHello() )
598 onNewSyncSource(src);
599 i++;
600 } while ( i < pkt.fh.block_count );
601 return cname_found;
602}
603
604bool QueueRTCPManager::onGotSDESChunk(SyncSource& source, SDESChunk& chunk, size_t len)
605{
606 bool cname_found = false;
607 bool end = false;
608
609 SyncSourceLink* srcLink = getLink(source);
610 Participant* part = source.getParticipant();
611
612 size_t pointer = sizeof(chunk.ssrc);
613
614 // process chunk items
615 while ( (pointer < len) && !end ) {
616 SDESItem* item =
617 reinterpret_cast<SDESItem*>(size_t(&(chunk)) + pointer);
618 if ( item->type > SDESItemTypeEND && item->type <= SDESItemTypeLast) {
619 pointer += sizeof(item->type) + sizeof(item->len) +
620 item->len;
621 if ( NULL == part && SDESItemTypeCNAME == item->type ) {
622 const RTPApplication& app = getApplication();
623 std::string cname = std::string(item->data,item->len);
624 const Participant* p = app.getParticipant(cname);
625 if ( p ) {
626 part = const_cast<Participant*>(p);
627 setParticipant(*(srcLink->getSource()),*part);
628 } else {
629 part = new Participant("-");
630 addParticipant(const_cast<RTPApplication&>(getApplication()),*part);
631 }
632 setParticipant(*(srcLink->getSource()),*part);
633 }
634
635 // support for CNAME updates
636 if ( part )
637 setSDESItem(part,(SDESItemType)item->type, item->data,item->len);
638
639 if ( item->type == SDESItemTypeCNAME) {
640 cname_found = true;
641 // note that CNAME must be send in
642 // every RTCP compound, so we only
643 // trust sources that include it.
644 setState(*(srcLink->getSource()),
645 SyncSource::stateActive);
646 }
647 } else if ( item->type == SDESItemTypeEND) {
648 end = true;
649 pointer++;
650 pointer += (pointer & 0x03); // padding
651 } else if ( item->type == SDESItemTypePRIV ) {
652 ptrdiff_t prevpointer = pointer;
653 uint8 plength = *( &(item->len) + 1 );
654 pointer += sizeof(item->type) + sizeof(item->len) + 1;
655
656 if ( part )
657 setSDESItem(part,SDESItemTypePRIV,
658 reinterpret_cast<char*>(item + pointer),plength);
659 pointer += plength;
660 setPRIVPrefix(part,
661 reinterpret_cast<char*>(item + pointer),
662 (item->len - 1 - plength));
663 pointer = prevpointer + item->len;
664 } else {
665 pointer++;
666 // TODO: error: SDES unknown
667 I( false );
668 }
669 }
670 return cname_found;
671}
672
673timeval QueueRTCPManager::computeRTCPInterval()
674{
675 float bwfract = controlBwFract * getSessionBandwidth();
676 uint32 participants = getMembersCount();
677 if ( getSendersCount() > 0 &&
678 ( getSendersCount() < (getMembersCount() * sendControlBwFract) )) {
679 // reserve "sendControlBwFract" fraction of the total
680 // RTCP bandwith for senders.
681 if (rtcpWeSent) {
682 // we take the side of active senders
683 bwfract *= sendControlBwFract;
684 participants = getSendersCount();
685 } else {
686 // we take the side of passive receivers
687 bwfract *= recvControlBwFract;
688 participants = getMembersCount() - getSendersCount();
689 }
690 }
691
692 microtimeout_t min_interval = rtcpMinInterval;
693 // be a bit quicker at first
694 if ( rtcpInitial )
695 min_interval /= 2;
696 // this is the real computation:
697 microtimeout_t interval = 0;
698 if ( bwfract != 0 ) {
699 interval = static_cast<microtimeout_t>
700 ((participants * rtcpAvgSize / bwfract) * 1000000);
701
702 if ( interval < rtcpMinInterval )
703 interval = rtcpMinInterval;
704 } else {
705 // 100 seconds instead of infinite
706 interval = 100000000;
707 }
708
709 interval = static_cast<microtimeout_t>(interval * ( 0.5 +
710 (rand() / (RAND_MAX + 1.0))));
711
712 timeval result;
713 result.tv_sec = interval / 1000000;
714 result.tv_usec = interval % 1000000;
715 return result;
716}
717
718size_t QueueRTCPManager::dispatchBYE(const std::string& reason)
719{
720 // for this method, see section 6.3.7 in RFC 3550
721 // never send a BYE packet if never sent an RTP or RTCP packet
722 // before
723 if ( !(getSendPacketCount() || getSendRTCPPacketCount()) )
724 return 0;
725
726 if ( getMembersCount() > 50) {
727 // Usurp the scheduler role and apply a back-off
728 // algorithm to avoid BYE floods.
729 gettimeofday(&(reconsInfo.rtcpTc),NULL);
730 reconsInfo.rtcpTp = reconsInfo.rtcpTc;
731 setMembersCount(1);
732 setPrevMembersNum(1);
733 rtcpInitial = true;
734 rtcpWeSent = false;
735 rtcpAvgSize = (uint16)(sizeof(RTCPFixedHeader) + sizeof(uint32) +
736 strlen(reason.c_str()) +
737 (4 - (strlen(reason.c_str()) & 0x03)));
738 gettimeofday(&(reconsInfo.rtcpTc),NULL);
739 timeval T = computeRTCPInterval();
740 timeradd(&(reconsInfo.rtcpTp),&T,&(reconsInfo.rtcpTn));
741 while ( timercmp(&(reconsInfo.rtcpTc),&(reconsInfo.rtcpTn),<) ) {
742 getOnlyBye();
743 if ( timerReconsideration() )
744 break;
745 gettimeofday(&(reconsInfo.rtcpTc),NULL);
746 }
747 }
748
749
750 unsigned char buffer[500];
751 // Build an empty RR as first packet in the compound.
752 // TODO: provide more information if available. Not really
753 // important, since this is the last packet being sent.
754 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(buffer);
755 pkt->fh.version = CCRTP_VERSION;
756 pkt->fh.padding = 0;
757 pkt->fh.block_count = 0;
758 pkt->fh.type = RTCPPacket::tRR;
759 pkt->info.RR.ssrc= getLocalSSRCNetwork();
760 uint16 len1 = sizeof(RTCPFixedHeader) + sizeof(uint32); // 1st pkt len.
761 pkt->fh.length = htons((len1 >> 2) - 1);
762 uint16 len = len1; // whole compound len.
763 // build a BYE packet
764 uint16 padlen = 0;
765 pkt = reinterpret_cast<RTCPPacket*>(buffer + len1);
766 pkt->fh.version = CCRTP_VERSION;
767 pkt->fh.block_count = 1;
768 pkt->fh.type = RTCPPacket::tBYE;
769 // add the SSRC identifier
770 pkt->info.BYE.ssrc = getLocalSSRCNetwork();
771 len += sizeof(RTCPFixedHeader) + sizeof(BYEPacket);
772 // add the optional reason
773 if ( reason.c_str() != NULL ){
774 pkt->info.BYE.length = (uint8)strlen(reason.c_str());
775 memcpy(buffer + len,reason.c_str(),pkt->info.BYE.length);
776 len += pkt->info.BYE.length;
777 padlen = 4 - ((len - len1) & 0x03);
778 if ( padlen ) {
779 memset(buffer + len,0,padlen);
780 len += padlen;
781 pkt->info.BYE.length += padlen;
782 }
783 }
784 pkt->fh.length = htons(((len - len1) >> 2) - 1);
785
786 return sendControlToDestinations(buffer,len);
787}
788
789void QueueRTCPManager::getOnlyBye()
790{
791 // This method is kind of simplified recvControl
792 timeval wait;
793 timersub(&(reconsInfo.rtcpTn),&(reconsInfo.rtcpTc),&wait);
794 microtimeout_t timer = wait.tv_usec/1000 + wait.tv_sec * 1000;
795 // wait up to reconsInfo.rtcpTn
796 if ( !isPendingControl(timer) )
797 return;
798
799 size_t len = 0;
800 InetHostAddress network_address;
801 tpport_t transport_port;
802 while ( (len = recvControl(rtcpRecvBuffer,getPathMTU(),
803 network_address,transport_port)) ) {
804 // Process a <code>len<code> octets long RTCP compound packet
805 // Check validity of the header fields of the compound packet
806 if ( !RTCPCompoundHandler::checkCompoundRTCPHeader(len) )
807 return;
808
809 // TODO: For now, we do nothing with the padding bit
810 // in the header.
811 uint32 pointer = 0;
812 RTCPPacket* pkt;
813 while ( pointer < len) {
814 pkt = reinterpret_cast<RTCPPacket*>
815 (rtcpRecvBuffer + pointer);
816
817 if (pkt->fh.type == RTCPPacket::tBYE ) {
818 bool created;
819 SyncSourceLink* srcLink =
820 getSourceBySSRC(pkt->getSSRC(),
821 created);
822 if( srcLink->getGoodbye() )
823 onGotGoodbye(*(srcLink->getSource()), "");
824 BYESource(pkt->getSSRC());
825 }
826 pointer += pkt->getLength();
827 }
828 }
829}
830
831size_t QueueRTCPManager::dispatchControlPacket(void)
832{
833 rtcpInitial = false;
834 // Keep in mind: always include a report (in SR or RR) and at
835 // least a SDES with the local CNAME. It is mandatory.
836
837 // (A) SR or RR, depending on whether we sent.
838 // pkt will point to the packets of the compound
839
840 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer);
841 // Fixed header of the first report
842 pkt->fh.padding = 0;
843 pkt->fh.version = CCRTP_VERSION;
844 // length of the RTCP compound packet. It will increase till
845 // the end of this routine. Both sender and receiver report
846 // carry the general 32-bit long fixed header and a 32-bit
847 // long SSRC identifier.
848 uint16 len = sizeof(RTCPFixedHeader) + sizeof(uint32);
849
850 // the fields block_count and length will be filled in later
851 // now decide whether to send a SR or a SR
852 if ( lastSendPacketCount != getSendPacketCount() ) {
853 // we have sent rtp packets since last RTCP -> send SR
854 lastSendPacketCount = getSendPacketCount();
855 pkt->fh.type = RTCPPacket::tSR;
856 pkt->info.SR.ssrc = getLocalSSRCNetwork();
857
858 // Fill in sender info block. It would be more
859 // accurate if this were done as late as possible.
860 timeval now;
861 gettimeofday(&now,NULL);
862 // NTP MSB and MSB: dependent on current payload type.
863 pkt->info.SR.sinfo.NTPMSW = htonl(now.tv_sec + NTP_EPOCH_OFFSET);
864 pkt->info.SR.sinfo.NTPLSW = htonl((uint32)(((double)(now.tv_usec)*(uint32)(~0))/1000000.0));
865 // RTP timestamp
866 int32 tstamp = now.tv_usec - getInitialTime().tv_usec;
867 tstamp *= (getCurrentRTPClockRate()/1000);
868 tstamp /= 1000;
869 tstamp += (now.tv_sec - getInitialTime().tv_sec) *
870 getCurrentRTPClockRate();
871 tstamp += getInitialTimestamp();
872 pkt->info.SR.sinfo.RTPTimestamp = htonl(tstamp);
873 // sender's packet and octet count
874 pkt->info.SR.sinfo.packetCount = htonl(getSendPacketCount());
875 pkt->info.SR.sinfo.octetCount = htonl(getSendOctetCount());
876 len += sizeof(SenderInfo);
877 } else {
878 // RR
879 pkt->fh.type = RTCPPacket::tRR;
880 pkt->info.RR.ssrc = getLocalSSRCNetwork();
881 }
882
883 // (B) put report blocks
884 // After adding report blocks, we have to leave room for at
885 // least a CNAME SDES item
886 uint16 available = (uint16)(getPathMTU()
887 - lowerHeadersSize
888 - len
889 - (sizeof(RTCPFixedHeader) +
890 2*sizeof(uint8) +
891 getApplication().getSDESItem(SDESItemTypeCNAME).length())
892 - 100);
893
894 // if we have to go to a new RR packet
895 bool another = false;
896 uint16 prevlen = 0;
897 RRBlock* reports;
898 if ( RTCPPacket::tRR == pkt->fh.type )
899 reports = pkt->info.RR.blocks;
900 else // ( RTCPPacket::tSR == pkt->fh.type )
901 reports = pkt->info.SR.blocks;
902 do {
903 uint8 blocks = 0;
904 pkt->fh.block_count = blocks = packReportBlocks(reports,len,available);
905 // the length field specifies 32-bit words
906 pkt->fh.length = htons( ((len - prevlen) >> 2) - 1);
907 prevlen = len;
908 if ( 31 == blocks ) {
909 // we would need room for a new RR packet and
910 // a CNAME SDES
911 if ( len < (available -
912 ( sizeof(RTCPFixedHeader) + sizeof(uint32) +
913 sizeof(RRBlock))) ) {
914 another = true;
915 // Header for this new packet in the compound
916 pkt = reinterpret_cast<RTCPPacket*>
917 (rtcpSendBuffer + len);
918 pkt->fh.version = CCRTP_VERSION;
919 pkt->fh.padding = 0;
920 pkt->fh.type = RTCPPacket::tRR;
921 pkt->info.RR.ssrc = getLocalSSRCNetwork();
922 // appended a new Header and a report block
923
924 len += sizeof(RTCPFixedHeader)+ sizeof(uint32);
925 reports = pkt->info.RR.blocks;
926 } else {
927 another = false;
928 }
929 } else {
930 another = false;
931 }
932 } while ( (len < available) && another );
933
934 // (C) SDES (CNAME)
935 // each SDES chunk must be 32-bit multiple long
936 // fill the padding with 0s
937 packSDES(len);
938
939 // TODO: virtual for sending APP RTCP packets?
940
941 // actually send the packet.
942 size_t count = sendControlToDestinations(rtcpSendBuffer,len);
943 ctrlSendCount++;
944 // Everything went right, update the RTCP average size
945 updateAvgRTCPSize(len);
946
947 return count;
948}
949
950void QueueRTCPManager::packSDES(uint16 &len)
951{
952 uint16 prevlen = len;
953 RTCPPacket* pkt = reinterpret_cast<RTCPPacket*>(rtcpSendBuffer + len);
954 // Fill RTCP fixed header. Note fh.length is not set till the
955 // end of this routine.
956 pkt->fh.version = CCRTP_VERSION;
957 pkt->fh.padding = 0;
958 pkt->fh.block_count = 1;
959 pkt->fh.type = RTCPPacket::tSDES;
960 pkt->info.SDES.ssrc = getLocalSSRCNetwork();
961 pkt->info.SDES.item.type = SDESItemTypeCNAME;
962 // put CNAME
963 size_t cnameLen =
964 getApplication().getSDESItem(SDESItemTypeCNAME).length();
965 const char* cname =
966 getApplication().getSDESItem(SDESItemTypeCNAME).c_str();
967 pkt->info.SDES.item.len = (uint8)cnameLen;
968 len += sizeof(RTCPFixedHeader) + sizeof(pkt->info.SDES.ssrc) +
969 sizeof(pkt->info.SDES.item.type) +
970 sizeof(pkt->info.SDES.item.len);
971
972 memcpy((rtcpSendBuffer + len),cname,cnameLen);
973 len += (uint16)cnameLen;
974 // pack items other than CNAME (following priorities
975 // stablished inside scheduleSDESItem()).
976 SDESItemType nexttype = scheduleSDESItem();
977 if ( (nexttype > SDESItemTypeCNAME) &&
978 (nexttype <= SDESItemTypeLast ) ) {
979 SDESItem *item = reinterpret_cast<SDESItem *>(rtcpSendBuffer + len);
980 item->type = nexttype;
981 const char *content =
982 getApplication().getSDESItem(nexttype).c_str();
983 item->len = (uint8)strlen(content);
984 len += 2;
985 memcpy(reinterpret_cast<char *>(rtcpSendBuffer + len),
986 content,item->len);
987 len += item->len;
988 }
989
990 // pack END item (terminate list of items in this chunk)
991 rtcpSendBuffer[len] = SDESItemTypeEND;
992 len++;
993
994 uint8 padding = len & 0x03;
995 if ( padding ) {
996 padding = 4 - padding;
997 memset((rtcpSendBuffer + len),SDESItemTypeEND,padding);
998 len += padding;
999 }
1000 pkt->fh.length = htons((len - prevlen - 1) >>2);
1001}
1002
1003uint8 QueueRTCPManager::packReportBlocks(RRBlock* blocks, uint16 &len, uint16& available)
1004{
1005 uint8 j = 0;
1006 // pack as many report blocks as we can
1007 SyncSourceLink* i = getFirst();
1008 for ( ;
1009 ( ( i != NULL ) &&
1010 ( len < (available - sizeof(RTCPCompoundHandler::RRBlock)) ) &&
1011 ( j < 31 ) );
1012 i = i->getNext() ) {
1013 SyncSourceLink& srcLink = *i;
1014 // update stats.
1015 srcLink.computeStats();
1016 blocks[j].ssrc = htonl(srcLink.getSource()->getID());
1017 blocks[j].rinfo.fractionLost = srcLink.getFractionLost();
1018 blocks[j].rinfo.lostMSB =
1019 (srcLink.getCumulativePacketLost() & 0xFF0000) >> 16;
1020 blocks[j].rinfo.lostLSW =
1021 htons(srcLink.getCumulativePacketLost() & 0xFFFF);
1022 blocks[j].rinfo.highestSeqNum =
1023 htonl(srcLink.getExtendedMaxSeqNum());
1024 blocks[j].rinfo.jitter =
1025 htonl(static_cast<uint32>(srcLink.getJitter()));
1026 RTCPCompoundHandler::SenderInfo* si =
1027 reinterpret_cast<RTCPCompoundHandler::SenderInfo*>(srcLink.getSenderInfo());
1028 if ( NULL == si ) {
1029 blocks[j].rinfo.lsr = 0;
1030 blocks[j].rinfo.dlsr = 0;
1031 } else {
1032 blocks[j].rinfo.lsr =
1033 htonl( ((ntohl(si->NTPMSW) & 0x0FFFF) << 16 )+
1034 ((ntohl(si->NTPLSW) & 0xFFFF0000) >> 16)
1035 );
1036 timeval now, diff;
1037 gettimeofday(&now,NULL);
1038 timeval last = srcLink.getLastRTCPSRTime();
1039 timersub(&now,&last,&diff);
1040 blocks[j].rinfo.dlsr =
1041 htonl(timevalIntervalTo65536(diff));
1042 }
1043 len += sizeof(RTCPCompoundHandler::RRBlock);
1044 j++;
1045 }
1046 return j;
1047}
1048
1049void QueueRTCPManager::setSDESItem(Participant* part, SDESItemType type,
1050const char* const value, size_t len)
1051{
1052 char* buf = new char[len + 1];
1053 memcpy(buf,value,len);
1054 buf[len] = '\0';
1055 ParticipantHandler::setSDESItem(part,type,buf);
1056 delete [] buf;
1057}
1058
1059void QueueRTCPManager::setPRIVPrefix(Participant* part, const char* const value, size_t len)
1060{
1061 char *buf = new char[len + 1];
1062 memcpy(buf,value,len);
1063 buf[len] = '\0';
1064 ParticipantHandler::setPRIVPrefix(part,buf);
1065 delete buf;
1066}
1067
1068SDESItemType QueueRTCPManager::scheduleSDESItem()
1069{
1070 uint8 i = 0;
1071 // TODO: follow, at least, standard priorities
1072 SDESItemType type = nextScheduledSDESItem;
1073
1074 while ( (queueApplication.getSDESItem(type).length() <= 0) &&
1075 i < (lastSchedulable - firstSchedulable) ) {
1076 i++;
1077 type = nextSDESType(type);
1078 }
1079 bool empty = true;
1080 if ( queueApplication.getSDESItem(type).length() > 0 )
1081 empty = false;
1082 nextScheduledSDESItem = nextSDESType(type);
1083 if ( empty )
1084 return SDESItemTypeEND;
1085 else
1086 return type;
1087}
1088
1089SDESItemType QueueRTCPManager::nextSDESType(SDESItemType t)
1090{
1091 t = static_cast<SDESItemType>( static_cast<int>(t) + 1 );
1092 if ( t > lastSchedulable )
1093 t = firstSchedulable;
1094 return t;
1095}
1096
1097size_t QueueRTCPManager::sendControlToDestinations(unsigned char* buffer, size_t len)
1098{
1099 size_t count = 0;
1100 lockDestinationList();
1101 if ( isSingleDestination() ) {
1102 count = sendControl(buffer,len);
1103 } else {
1104 // when no destination has been added, NULL == dest.
1105 for (std::list<TransportAddress*>::iterator i =
1106 destList.begin(); destList.end() != i; i++) {
1107 TransportAddress* dest = *i;
1108 setControlPeer(dest->getNetworkAddress(),
1109 dest->getControlTransportPort());
1110 count += sendControl(buffer,len);
1111 }
1112 }
1113 unlockDestinationList();
1114
1115 return count;
1116}
1117
1118#ifdef CCXX_NAMESPACES
1119}
1120#endif
1121
1122/** EMACS **
1123 * Local variables:
1124 * mode: c++
1125 * c-basic-offset: 4
1126 * End:
1127 */