| 1 | /********** | 
|---|
| 2 | This library is free software; you can redistribute it and/or modify it under | 
|---|
| 3 | the terms of the GNU Lesser General Public License as published by the | 
|---|
| 4 | Free Software Foundation; either version 3 of the License, or (at your | 
|---|
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) | 
|---|
| 6 |  | 
|---|
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|---|
| 9 | FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for | 
|---|
| 10 | more details. | 
|---|
| 11 |  | 
|---|
| 12 | You should have received a copy of the GNU Lesser General Public License | 
|---|
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., | 
|---|
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA | 
|---|
| 15 | **********/ | 
|---|
| 16 | // "liveMedia" | 
|---|
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc.  All rights reserved. | 
|---|
| 18 | // RTCP | 
|---|
| 19 | // Implementation | 
|---|
| 20 |  | 
|---|
| 21 | #include "RTCP.hh" | 
|---|
| 22 | #include "GroupsockHelper.hh" | 
|---|
| 23 | #include "rtcp_from_spec.h" | 
|---|
| 24 | #if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) | 
|---|
| 25 | #define snprintf _snprintf | 
|---|
| 26 | #endif | 
|---|
| 27 |  | 
|---|
| 28 | ////////// RTCPMemberDatabase ////////// | 
|---|
| 29 |  | 
|---|
| 30 | class RTCPMemberDatabase { | 
|---|
| 31 | public: | 
|---|
| 32 | RTCPMemberDatabase(RTCPInstance& ourRTCPInstance) | 
|---|
| 33 | : fOurRTCPInstance(ourRTCPInstance), fNumMembers(1 /*ourself*/), | 
|---|
| 34 | fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { | 
|---|
| 35 | } | 
|---|
| 36 |  | 
|---|
| 37 | virtual ~RTCPMemberDatabase() { | 
|---|
| 38 | delete fTable; | 
|---|
| 39 | } | 
|---|
| 40 |  | 
|---|
| 41 | Boolean isMember(u_int32_t ssrc) const { | 
|---|
| 42 | return fTable->Lookup((char*)(long)ssrc) != NULL; | 
|---|
| 43 | } | 
|---|
| 44 |  | 
|---|
| 45 | Boolean noteMembership(u_int32_t ssrc, unsigned curTimeCount) { | 
|---|
| 46 | Boolean isNew = !isMember(ssrc); | 
|---|
| 47 |  | 
|---|
| 48 | if (isNew) { | 
|---|
| 49 | ++fNumMembers; | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | // Record the current time, so we can age stale members | 
|---|
| 53 | fTable->Add((char*)(long)ssrc, (void*)(long)curTimeCount); | 
|---|
| 54 |  | 
|---|
| 55 | return isNew; | 
|---|
| 56 | } | 
|---|
| 57 |  | 
|---|
| 58 | Boolean remove(u_int32_t ssrc) { | 
|---|
| 59 | Boolean wasPresent = fTable->Remove((char*)(long)ssrc); | 
|---|
| 60 | if (wasPresent) { | 
|---|
| 61 | --fNumMembers; | 
|---|
| 62 | } | 
|---|
| 63 | return wasPresent; | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 | unsigned numMembers() const { | 
|---|
| 67 | return fNumMembers; | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | void reapOldMembers(unsigned threshold); | 
|---|
| 71 |  | 
|---|
| 72 | private: | 
|---|
| 73 | RTCPInstance& fOurRTCPInstance; | 
|---|
| 74 | unsigned fNumMembers; | 
|---|
| 75 | HashTable* fTable; | 
|---|
| 76 | }; | 
|---|
| 77 |  | 
|---|
| 78 | void RTCPMemberDatabase::reapOldMembers(unsigned threshold) { | 
|---|
| 79 | Boolean foundOldMember; | 
|---|
| 80 | u_int32_t oldSSRC = 0; | 
|---|
| 81 |  | 
|---|
| 82 | do { | 
|---|
| 83 | foundOldMember = False; | 
|---|
| 84 |  | 
|---|
| 85 | HashTable::Iterator* iter | 
|---|
| 86 | = HashTable::Iterator::create(*fTable); | 
|---|
| 87 | uintptr_t timeCount; | 
|---|
| 88 | char const* key; | 
|---|
| 89 | while ((timeCount = (uintptr_t)(iter->next(key))) != 0) { | 
|---|
| 90 | #ifdef DEBUG | 
|---|
| 91 | fprintf(stderr, "reap: checking SSRC 0x%lx: %ld (threshold %d)\n", (unsigned long)key, timeCount, threshold); | 
|---|
| 92 | #endif | 
|---|
| 93 | if (timeCount < (uintptr_t)threshold) { // this SSRC is old | 
|---|
| 94 | uintptr_t ssrc = (uintptr_t)key; | 
|---|
| 95 | oldSSRC = (u_int32_t)ssrc; | 
|---|
| 96 | foundOldMember = True; | 
|---|
| 97 | } | 
|---|
| 98 | } | 
|---|
| 99 | delete iter; | 
|---|
| 100 |  | 
|---|
| 101 | if (foundOldMember) { | 
|---|
| 102 | #ifdef DEBUG | 
|---|
| 103 | fprintf(stderr, "reap: removing SSRC 0x%x\n", oldSSRC); | 
|---|
| 104 | #endif | 
|---|
| 105 | fOurRTCPInstance.removeSSRC(oldSSRC, True); | 
|---|
| 106 | } | 
|---|
| 107 | } while (foundOldMember); | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 |  | 
|---|
| 111 | ////////// RTCPInstance ////////// | 
|---|
| 112 |  | 
|---|
| 113 | static double dTimeNow() { | 
|---|
| 114 | struct timeval timeNow; | 
|---|
| 115 | gettimeofday(&timeNow, NULL); | 
|---|
| 116 | return (double) (timeNow.tv_sec + timeNow.tv_usec/1000000.0); | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | static unsigned const maxRTCPPacketSize = 1456; | 
|---|
| 120 | // bytes (1500, minus some allowance for IP, UDP, UMTP headers) | 
|---|
| 121 | static unsigned const preferredRTCPPacketSize = 1000; // bytes | 
|---|
| 122 |  | 
|---|
| 123 | RTCPInstance::RTCPInstance(UsageEnvironment& env, Groupsock* RTCPgs, | 
|---|
| 124 | unsigned totSessionBW, | 
|---|
| 125 | unsigned char const* cname, | 
|---|
| 126 | RTPSink* sink, RTPSource* source, | 
|---|
| 127 | Boolean isSSMSource) | 
|---|
| 128 | : Medium(env), fRTCPInterface(this, RTCPgs), fTotSessionBW(totSessionBW), | 
|---|
| 129 | fSink(sink), fSource(source), fIsSSMSource(isSSMSource), | 
|---|
| 130 | fCNAME(RTCP_SDES_CNAME, cname), fOutgoingReportCount(1), | 
|---|
| 131 | fAveRTCPSize(0), fIsInitial(1), fPrevNumMembers(0), | 
|---|
| 132 | fLastSentSize(0), fLastReceivedSize(0), fLastReceivedSSRC(0), | 
|---|
| 133 | fTypeOfEvent(EVENT_UNKNOWN), fTypeOfPacket(PACKET_UNKNOWN_TYPE), | 
|---|
| 134 | fHaveJustSentPacket(False), fLastPacketSentSize(0), | 
|---|
| 135 | fByeHandlerTask(NULL), fByeWithReasonHandlerTask(NULL), fByeHandlerClientData(NULL), | 
|---|
| 136 | fSRHandlerTask(NULL), fSRHandlerClientData(NULL), | 
|---|
| 137 | fRRHandlerTask(NULL), fRRHandlerClientData(NULL), | 
|---|
| 138 | fSpecificRRHandlerTable(NULL), | 
|---|
| 139 | fAppHandlerTask(NULL), fAppHandlerClientData(NULL) { | 
|---|
| 140 | #ifdef DEBUG | 
|---|
| 141 | fprintf(stderr, "RTCPInstance[%p]::RTCPInstance()\n", this); | 
|---|
| 142 | #endif | 
|---|
| 143 | if (fTotSessionBW == 0) { // not allowed! | 
|---|
| 144 | env << "RTCPInstance::RTCPInstance error: totSessionBW parameter should not be zero!\n"; | 
|---|
| 145 | fTotSessionBW = 1; | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | if (isSSMSource) RTCPgs->multicastSendOnly(); // don't receive multicast | 
|---|
| 149 |  | 
|---|
| 150 | double timeNow = dTimeNow(); | 
|---|
| 151 | fPrevReportTime = fNextReportTime = timeNow; | 
|---|
| 152 |  | 
|---|
| 153 | fKnownMembers = new RTCPMemberDatabase(*this); | 
|---|
| 154 | fInBuf = new unsigned char[maxRTCPPacketSize]; | 
|---|
| 155 | if (fKnownMembers == NULL || fInBuf == NULL) return; | 
|---|
| 156 | fNumBytesAlreadyRead = 0; | 
|---|
| 157 |  | 
|---|
| 158 | fOutBuf = new OutPacketBuffer(preferredRTCPPacketSize, maxRTCPPacketSize, maxRTCPPacketSize); | 
|---|
| 159 | if (fOutBuf == NULL) return; | 
|---|
| 160 |  | 
|---|
| 161 | if (fSource != NULL && fSource->RTPgs() == RTCPgs) { | 
|---|
| 162 | // We're receiving RTCP reports that are multiplexed with RTP, so ask the RTP source | 
|---|
| 163 | // to give them to us: | 
|---|
| 164 | fSource->registerForMultiplexedRTCPPackets(this); | 
|---|
| 165 | } else { | 
|---|
| 166 | // Arrange to handle incoming reports from the network: | 
|---|
| 167 | TaskScheduler::BackgroundHandlerProc* handler | 
|---|
| 168 | = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; | 
|---|
| 169 | fRTCPInterface.startNetworkReading(handler); | 
|---|
| 170 | } | 
|---|
| 171 |  | 
|---|
| 172 | // Send our first report. | 
|---|
| 173 | fTypeOfEvent = EVENT_REPORT; | 
|---|
| 174 | onExpire(this); | 
|---|
| 175 | } | 
|---|
| 176 |  | 
|---|
| 177 | struct RRHandlerRecord { | 
|---|
| 178 | TaskFunc* rrHandlerTask; | 
|---|
| 179 | void* rrHandlerClientData; | 
|---|
| 180 | }; | 
|---|
| 181 |  | 
|---|
| 182 | RTCPInstance::~RTCPInstance() { | 
|---|
| 183 | #ifdef DEBUG | 
|---|
| 184 | fprintf(stderr, "RTCPInstance[%p]::~RTCPInstance()\n", this); | 
|---|
| 185 | #endif | 
|---|
| 186 | // Begin by sending a BYE.  We have to do this immediately, without | 
|---|
| 187 | // 'reconsideration', because "this" is going away. | 
|---|
| 188 | fTypeOfEvent = EVENT_BYE; // not used, but... | 
|---|
| 189 | sendBYE(); | 
|---|
| 190 |  | 
|---|
| 191 | if (fSource != NULL && fSource->RTPgs() == fRTCPInterface.gs()) { | 
|---|
| 192 | // We were receiving RTCP reports that were multiplexed with RTP, so tell the RTP source | 
|---|
| 193 | // to stop giving them to us: | 
|---|
| 194 | fSource->deregisterForMultiplexedRTCPPackets(); | 
|---|
| 195 | fRTCPInterface.forgetOurGroupsock(); | 
|---|
| 196 | // so that the "fRTCPInterface" destructor doesn't turn off background read handling | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | if (fSpecificRRHandlerTable != NULL) { | 
|---|
| 200 | AddressPortLookupTable::Iterator iter(*fSpecificRRHandlerTable); | 
|---|
| 201 | RRHandlerRecord* rrHandler; | 
|---|
| 202 | while ((rrHandler = (RRHandlerRecord*)iter.next()) != NULL) { | 
|---|
| 203 | delete rrHandler; | 
|---|
| 204 | } | 
|---|
| 205 | delete fSpecificRRHandlerTable; | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | delete fKnownMembers; | 
|---|
| 209 | delete fOutBuf; | 
|---|
| 210 | delete[] fInBuf; | 
|---|
| 211 | } | 
|---|
| 212 |  | 
|---|
| 213 | void RTCPInstance::noteArrivingRR(struct sockaddr_in const& fromAddressAndPort, | 
|---|
| 214 | int tcpSocketNum, unsigned char tcpStreamChannelId) { | 
|---|
| 215 | // If a 'RR handler' was set, call it now: | 
|---|
| 216 |  | 
|---|
| 217 | // Specific RR handler: | 
|---|
| 218 | if (fSpecificRRHandlerTable != NULL) { | 
|---|
| 219 | netAddressBits fromAddr; | 
|---|
| 220 | portNumBits fromPortNum; | 
|---|
| 221 | if (tcpSocketNum < 0) { | 
|---|
| 222 | // Normal case: We read the RTCP packet over UDP | 
|---|
| 223 | fromAddr = fromAddressAndPort.sin_addr.s_addr; | 
|---|
| 224 | fromPortNum = ntohs(fromAddressAndPort.sin_port); | 
|---|
| 225 | } else { | 
|---|
| 226 | // Special case: We read the RTCP packet over TCP (interleaved) | 
|---|
| 227 | // Hack: Use the TCP socket and channel id to look up the handler | 
|---|
| 228 | fromAddr = tcpSocketNum; | 
|---|
| 229 | fromPortNum = tcpStreamChannelId; | 
|---|
| 230 | } | 
|---|
| 231 | Port fromPort(fromPortNum); | 
|---|
| 232 | RRHandlerRecord* rrHandler | 
|---|
| 233 | = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddr, (~0), fromPort)); | 
|---|
| 234 | if (rrHandler != NULL) { | 
|---|
| 235 | if (rrHandler->rrHandlerTask != NULL) { | 
|---|
| 236 | (*(rrHandler->rrHandlerTask))(rrHandler->rrHandlerClientData); | 
|---|
| 237 | } | 
|---|
| 238 | } | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | // General RR handler: | 
|---|
| 242 | if (fRRHandlerTask != NULL) (*fRRHandlerTask)(fRRHandlerClientData); | 
|---|
| 243 | } | 
|---|
| 244 |  | 
|---|
| 245 | RTCPInstance* RTCPInstance::createNew(UsageEnvironment& env, Groupsock* RTCPgs, | 
|---|
| 246 | unsigned totSessionBW, | 
|---|
| 247 | unsigned char const* cname, | 
|---|
| 248 | RTPSink* sink, RTPSource* source, | 
|---|
| 249 | Boolean isSSMSource) { | 
|---|
| 250 | return new RTCPInstance(env, RTCPgs, totSessionBW, cname, sink, source, | 
|---|
| 251 | isSSMSource); | 
|---|
| 252 | } | 
|---|
| 253 |  | 
|---|
| 254 | Boolean RTCPInstance::lookupByName(UsageEnvironment& env, | 
|---|
| 255 | char const* instanceName, | 
|---|
| 256 | RTCPInstance*& resultInstance) { | 
|---|
| 257 | resultInstance = NULL; // unless we succeed | 
|---|
| 258 |  | 
|---|
| 259 | Medium* medium; | 
|---|
| 260 | if (!Medium::lookupByName(env, instanceName, medium)) return False; | 
|---|
| 261 |  | 
|---|
| 262 | if (!medium->isRTCPInstance()) { | 
|---|
| 263 | env.setResultMsg(instanceName, " is not a RTCP instance"); | 
|---|
| 264 | return False; | 
|---|
| 265 | } | 
|---|
| 266 |  | 
|---|
| 267 | resultInstance = (RTCPInstance*)medium; | 
|---|
| 268 | return True; | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | Boolean RTCPInstance::isRTCPInstance() const { | 
|---|
| 272 | return True; | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | unsigned RTCPInstance::numMembers() const { | 
|---|
| 276 | if (fKnownMembers == NULL) return 0; | 
|---|
| 277 |  | 
|---|
| 278 | return fKnownMembers->numMembers(); | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | void RTCPInstance::setByeHandler(TaskFunc* handlerTask, void* clientData, | 
|---|
| 282 | Boolean handleActiveParticipantsOnly) { | 
|---|
| 283 | fByeHandlerTask = handlerTask; | 
|---|
| 284 | fByeWithReasonHandlerTask = NULL; | 
|---|
| 285 | fByeHandlerClientData = clientData; | 
|---|
| 286 | fByeHandleActiveParticipantsOnly = handleActiveParticipantsOnly; | 
|---|
| 287 | } | 
|---|
| 288 |  | 
|---|
| 289 | void RTCPInstance::setByeWithReasonHandler(ByeWithReasonHandlerFunc* handlerTask, void* clientData, | 
|---|
| 290 | Boolean handleActiveParticipantsOnly) { | 
|---|
| 291 | fByeHandlerTask = NULL; | 
|---|
| 292 | fByeWithReasonHandlerTask = handlerTask; | 
|---|
| 293 | fByeHandlerClientData = clientData; | 
|---|
| 294 | fByeHandleActiveParticipantsOnly = handleActiveParticipantsOnly; | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 | void RTCPInstance::setSRHandler(TaskFunc* handlerTask, void* clientData) { | 
|---|
| 298 | fSRHandlerTask = handlerTask; | 
|---|
| 299 | fSRHandlerClientData = clientData; | 
|---|
| 300 | } | 
|---|
| 301 |  | 
|---|
| 302 | void RTCPInstance::setRRHandler(TaskFunc* handlerTask, void* clientData) { | 
|---|
| 303 | fRRHandlerTask = handlerTask; | 
|---|
| 304 | fRRHandlerClientData = clientData; | 
|---|
| 305 | } | 
|---|
| 306 |  | 
|---|
| 307 | void RTCPInstance | 
|---|
| 308 | ::setSpecificRRHandler(netAddressBits fromAddress, Port fromPort, | 
|---|
| 309 | TaskFunc* handlerTask, void* clientData) { | 
|---|
| 310 | if (handlerTask == NULL && clientData == NULL) { | 
|---|
| 311 | unsetSpecificRRHandler(fromAddress, fromPort); | 
|---|
| 312 | return; | 
|---|
| 313 | } | 
|---|
| 314 |  | 
|---|
| 315 | RRHandlerRecord* rrHandler = new RRHandlerRecord; | 
|---|
| 316 | rrHandler->rrHandlerTask = handlerTask; | 
|---|
| 317 | rrHandler->rrHandlerClientData = clientData; | 
|---|
| 318 | if (fSpecificRRHandlerTable == NULL) { | 
|---|
| 319 | fSpecificRRHandlerTable = new AddressPortLookupTable; | 
|---|
| 320 | } | 
|---|
| 321 | RRHandlerRecord* existingRecord = (RRHandlerRecord*)fSpecificRRHandlerTable->Add(fromAddress, (~0), fromPort, rrHandler); | 
|---|
| 322 | delete existingRecord; // if any | 
|---|
| 323 |  | 
|---|
| 324 | } | 
|---|
| 325 |  | 
|---|
| 326 | void RTCPInstance | 
|---|
| 327 | ::unsetSpecificRRHandler(netAddressBits fromAddress, Port fromPort) { | 
|---|
| 328 | if (fSpecificRRHandlerTable == NULL) return; | 
|---|
| 329 |  | 
|---|
| 330 | RRHandlerRecord* rrHandler | 
|---|
| 331 | = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddress, (~0), fromPort)); | 
|---|
| 332 | if (rrHandler != NULL) { | 
|---|
| 333 | fSpecificRRHandlerTable->Remove(fromAddress, (~0), fromPort); | 
|---|
| 334 | delete rrHandler; | 
|---|
| 335 | } | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 | void RTCPInstance::setAppHandler(RTCPAppHandlerFunc* handlerTask, void* clientData) { | 
|---|
| 339 | fAppHandlerTask = handlerTask; | 
|---|
| 340 | fAppHandlerClientData = clientData; | 
|---|
| 341 | } | 
|---|
| 342 |  | 
|---|
| 343 | void RTCPInstance::sendAppPacket(u_int8_t subtype, char const* name, | 
|---|
| 344 | u_int8_t* appDependentData, unsigned appDependentDataSize) { | 
|---|
| 345 | // Set up the first 4 bytes: V,PT,subtype,PT,length: | 
|---|
| 346 | u_int32_t rtcpHdr = 0x80000000; // version 2, no padding | 
|---|
| 347 | rtcpHdr |= (subtype&0x1F)<<24; | 
|---|
| 348 | rtcpHdr |= (RTCP_PT_APP<<16); | 
|---|
| 349 | unsigned length = 2 + (appDependentDataSize+3)/4; | 
|---|
| 350 | rtcpHdr |= (length&0xFFFF); | 
|---|
| 351 | fOutBuf->enqueueWord(rtcpHdr); | 
|---|
| 352 |  | 
|---|
| 353 | // Set up the next 4 bytes: SSRC: | 
|---|
| 354 | fOutBuf->enqueueWord(fSource != NULL ? fSource->SSRC() : fSink != NULL ? fSink->SSRC() : 0); | 
|---|
| 355 |  | 
|---|
| 356 | // Set up the next 4 bytes: name: | 
|---|
| 357 | char nameBytes[4]; | 
|---|
| 358 | nameBytes[0] = nameBytes[1] = nameBytes[2] = nameBytes[3] = '\0'; // by default | 
|---|
| 359 | if (name != NULL) { | 
|---|
| 360 | snprintf(nameBytes, 4, "%s", name); | 
|---|
| 361 | } | 
|---|
| 362 | fOutBuf->enqueue((u_int8_t*)nameBytes, 4); | 
|---|
| 363 |  | 
|---|
| 364 | // Set up the remaining bytes (if any): application-dependent data (+ padding): | 
|---|
| 365 | if (appDependentData != NULL && appDependentDataSize > 0) { | 
|---|
| 366 | fOutBuf->enqueue(appDependentData, appDependentDataSize); | 
|---|
| 367 |  | 
|---|
| 368 | unsigned modulo = appDependentDataSize%4; | 
|---|
| 369 | unsigned paddingSize = modulo == 0 ? 0 : 4-modulo; | 
|---|
| 370 | u_int8_t const paddingByte = 0x00; | 
|---|
| 371 | for (unsigned i = 0; i < paddingSize; ++i) fOutBuf->enqueue(&paddingByte, 1); | 
|---|
| 372 | } | 
|---|
| 373 |  | 
|---|
| 374 | // Finally, send the packet: | 
|---|
| 375 | sendBuiltPacket(); | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | void RTCPInstance::setStreamSocket(int sockNum, | 
|---|
| 379 | unsigned char streamChannelId) { | 
|---|
| 380 | // Turn off background read handling: | 
|---|
| 381 | fRTCPInterface.stopNetworkReading(); | 
|---|
| 382 |  | 
|---|
| 383 | // Switch to RTCP-over-TCP: | 
|---|
| 384 | fRTCPInterface.setStreamSocket(sockNum, streamChannelId); | 
|---|
| 385 |  | 
|---|
| 386 | // Turn background reading back on: | 
|---|
| 387 | TaskScheduler::BackgroundHandlerProc* handler | 
|---|
| 388 | = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; | 
|---|
| 389 | fRTCPInterface.startNetworkReading(handler); | 
|---|
| 390 | } | 
|---|
| 391 |  | 
|---|
| 392 | void RTCPInstance::addStreamSocket(int sockNum, | 
|---|
| 393 | unsigned char streamChannelId) { | 
|---|
| 394 | // First, turn off background read handling for the default (UDP) socket: | 
|---|
| 395 | envir().taskScheduler().turnOffBackgroundReadHandling(fRTCPInterface.gs()->socketNum()); | 
|---|
| 396 |  | 
|---|
| 397 | // Add the RTCP-over-TCP interface: | 
|---|
| 398 | fRTCPInterface.addStreamSocket(sockNum, streamChannelId); | 
|---|
| 399 |  | 
|---|
| 400 | // Turn on background reading for this socket (in case it's not on already): | 
|---|
| 401 | TaskScheduler::BackgroundHandlerProc* handler | 
|---|
| 402 | = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; | 
|---|
| 403 | fRTCPInterface.startNetworkReading(handler); | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 | void RTCPInstance | 
|---|
| 407 | ::injectReport(u_int8_t const* packet, unsigned packetSize, struct sockaddr_in const& fromAddress) { | 
|---|
| 408 | if (packetSize > maxRTCPPacketSize) packetSize = maxRTCPPacketSize; | 
|---|
| 409 | memmove(fInBuf, packet, packetSize); | 
|---|
| 410 |  | 
|---|
| 411 | processIncomingReport(packetSize, fromAddress, -1, 0xFF); // assume report received over UDP | 
|---|
| 412 | } | 
|---|
| 413 |  | 
|---|
| 414 | static unsigned const IP_UDP_HDR_SIZE = 28; | 
|---|
| 415 | // overhead (bytes) of IP and UDP hdrs | 
|---|
| 416 |  | 
|---|
| 417 | #define ADVANCE(n) pkt += (n); packetSize -= (n) | 
|---|
| 418 |  | 
|---|
| 419 | void RTCPInstance::incomingReportHandler(RTCPInstance* instance, | 
|---|
| 420 | int /*mask*/) { | 
|---|
| 421 | instance->incomingReportHandler1(); | 
|---|
| 422 | } | 
|---|
| 423 |  | 
|---|
| 424 | void RTCPInstance::incomingReportHandler1() { | 
|---|
| 425 | do { | 
|---|
| 426 | if (fNumBytesAlreadyRead >= maxRTCPPacketSize) { | 
|---|
| 427 | envir() << "RTCPInstance error: Hit limit when reading incoming packet over TCP. (fNumBytesAlreadyRead (" | 
|---|
| 428 | << fNumBytesAlreadyRead << ") >= maxRTCPPacketSize ("<< maxRTCPPacketSize | 
|---|
| 429 | << ")).  The remote endpoint is using a buggy implementation of RTP/RTCP-over-TCP.  Please upgrade it!\n"; | 
|---|
| 430 | break; | 
|---|
| 431 | } | 
|---|
| 432 |  | 
|---|
| 433 | unsigned numBytesRead; | 
|---|
| 434 | struct sockaddr_in fromAddress; | 
|---|
| 435 | int tcpSocketNum; | 
|---|
| 436 | unsigned char tcpStreamChannelId; | 
|---|
| 437 | Boolean packetReadWasIncomplete; | 
|---|
| 438 | Boolean readResult | 
|---|
| 439 | = fRTCPInterface.handleRead(&fInBuf[fNumBytesAlreadyRead], maxRTCPPacketSize - fNumBytesAlreadyRead, | 
|---|
| 440 | numBytesRead, fromAddress, | 
|---|
| 441 | tcpSocketNum, tcpStreamChannelId, | 
|---|
| 442 | packetReadWasIncomplete); | 
|---|
| 443 |  | 
|---|
| 444 | unsigned packetSize = 0; | 
|---|
| 445 | if (packetReadWasIncomplete) { | 
|---|
| 446 | fNumBytesAlreadyRead += numBytesRead; | 
|---|
| 447 | return; // more reads are needed to get the entire packet | 
|---|
| 448 | } else { // normal case: We've read the entire packet | 
|---|
| 449 | packetSize = fNumBytesAlreadyRead + numBytesRead; | 
|---|
| 450 | fNumBytesAlreadyRead = 0; // for next time | 
|---|
| 451 | } | 
|---|
| 452 | if (!readResult) break; | 
|---|
| 453 |  | 
|---|
| 454 | // Ignore the packet if it was looped-back from ourself: | 
|---|
| 455 | Boolean packetWasFromOurHost = False; | 
|---|
| 456 | if (RTCPgs()->wasLoopedBackFromUs(envir(), fromAddress)) { | 
|---|
| 457 | packetWasFromOurHost = True; | 
|---|
| 458 | // However, we still want to handle incoming RTCP packets from | 
|---|
| 459 | // *other processes* on the same machine.  To distinguish this | 
|---|
| 460 | // case from a true loop-back, check whether we've just sent a | 
|---|
| 461 | // packet of the same size.  (This check isn't perfect, but it seems | 
|---|
| 462 | // to be the best we can do.) | 
|---|
| 463 | if (fHaveJustSentPacket && fLastPacketSentSize == packetSize) { | 
|---|
| 464 | // This is a true loop-back: | 
|---|
| 465 | fHaveJustSentPacket = False; | 
|---|
| 466 | break; // ignore this packet | 
|---|
| 467 | } | 
|---|
| 468 | } | 
|---|
| 469 |  | 
|---|
| 470 | if (fIsSSMSource && !packetWasFromOurHost) { | 
|---|
| 471 | // This packet is assumed to have been received via unicast (because we're a SSM source, | 
|---|
| 472 | // and SSM receivers send back RTCP "RR" packets via unicast). | 
|---|
| 473 | // 'Reflect' the packet by resending it to the multicast group, so that any other receivers | 
|---|
| 474 | // can also get to see it. | 
|---|
| 475 |  | 
|---|
| 476 | // NOTE: Denial-of-service attacks are possible here. | 
|---|
| 477 | // Users of this software may wish to add their own, | 
|---|
| 478 | // application-specific mechanism for 'authenticating' the | 
|---|
| 479 | // validity of this packet before reflecting it. | 
|---|
| 480 |  | 
|---|
| 481 | // NOTE: The test for "!packetWasFromOurHost" means that we won't reflect RTCP packets | 
|---|
| 482 | // that come from other processes on the same host as us.  The reason for this is that the | 
|---|
| 483 | // 'packet size' test above is not 100% reliable; some packets that were truly looped back | 
|---|
| 484 | // from us might not be detected as such, and this might lead to infinite | 
|---|
| 485 | // forwarding/receiving of some packets.  To avoid this possibility, we reflect only | 
|---|
| 486 | // RTCP packets that we know for sure originated elsewhere. | 
|---|
| 487 | // (Note, though, that if we ever re-enable the code in "Groupsock::multicastSendOnly()", | 
|---|
| 488 | // then we could remove the test for "!packetWasFromOurHost".) | 
|---|
| 489 | fRTCPInterface.sendPacket(fInBuf, packetSize); | 
|---|
| 490 | fHaveJustSentPacket = True; | 
|---|
| 491 | fLastPacketSentSize = packetSize; | 
|---|
| 492 | } | 
|---|
| 493 |  | 
|---|
| 494 | processIncomingReport(packetSize, fromAddress, tcpSocketNum, tcpStreamChannelId); | 
|---|
| 495 | } while (0); | 
|---|
| 496 | } | 
|---|
| 497 |  | 
|---|
| 498 | void RTCPInstance | 
|---|
| 499 | ::processIncomingReport(unsigned packetSize, struct sockaddr_in const& fromAddressAndPort, | 
|---|
| 500 | int tcpSocketNum, unsigned char tcpStreamChannelId) { | 
|---|
| 501 | do { | 
|---|
| 502 | Boolean callByeHandler = False; | 
|---|
| 503 | char* reason = NULL; // by default, unless/until a BYE packet with a 'reason' arrives | 
|---|
| 504 | unsigned char* pkt = fInBuf; | 
|---|
| 505 |  | 
|---|
| 506 | #ifdef DEBUG | 
|---|
| 507 | fprintf(stderr, "[%p]saw incoming RTCP packet (from ", this); | 
|---|
| 508 | if (tcpSocketNum < 0) { | 
|---|
| 509 | // Note that "fromAddressAndPort" is valid only if we're receiving over UDP (not over TCP): | 
|---|
| 510 | fprintf(stderr, "address %s, port %d", AddressString(fromAddressAndPort).val(), ntohs(fromAddressAndPort.sin_port)); | 
|---|
| 511 | } else { | 
|---|
| 512 | fprintf(stderr, "TCP socket #%d, stream channel id %d", tcpSocketNum, tcpStreamChannelId); | 
|---|
| 513 | } | 
|---|
| 514 | fprintf(stderr, ")\n"); | 
|---|
| 515 | for (unsigned i = 0; i < packetSize; ++i) { | 
|---|
| 516 | if (i%4 == 0) fprintf(stderr, " "); | 
|---|
| 517 | fprintf(stderr, "%02x", pkt[i]); | 
|---|
| 518 | } | 
|---|
| 519 | fprintf(stderr, "\n"); | 
|---|
| 520 | #endif | 
|---|
| 521 | int totPacketSize = IP_UDP_HDR_SIZE + packetSize; | 
|---|
| 522 |  | 
|---|
| 523 | // Check the RTCP packet for validity: | 
|---|
| 524 | // It must at least contain a header (4 bytes), and this header | 
|---|
| 525 | // must be version=2, with no padding bit, and a payload type of | 
|---|
| 526 | // SR (200), RR (201), or APP (204): | 
|---|
| 527 | if (packetSize < 4) break; | 
|---|
| 528 | unsigned rtcpHdr = ntohl(*(u_int32_t*)pkt); | 
|---|
| 529 | if ((rtcpHdr & 0xE0FE0000) != (0x80000000 | (RTCP_PT_SR<<16)) && | 
|---|
| 530 | (rtcpHdr & 0xE0FF0000) != (0x80000000 | (RTCP_PT_APP<<16))) { | 
|---|
| 531 | #ifdef DEBUG | 
|---|
| 532 | fprintf(stderr, "rejected bad RTCP packet: header 0x%08x\n", rtcpHdr); | 
|---|
| 533 | #endif | 
|---|
| 534 | break; | 
|---|
| 535 | } | 
|---|
| 536 |  | 
|---|
| 537 | // Process each of the individual RTCP 'subpackets' in (what may be) | 
|---|
| 538 | // a compound RTCP packet. | 
|---|
| 539 | int typeOfPacket = PACKET_UNKNOWN_TYPE; | 
|---|
| 540 | unsigned  = 0; | 
|---|
| 541 | Boolean packetOK = False; | 
|---|
| 542 | while (1) { | 
|---|
| 543 | u_int8_t rc = (rtcpHdr>>24)&0x1F; | 
|---|
| 544 | u_int8_t pt = (rtcpHdr>>16)&0xFF; | 
|---|
| 545 | unsigned length = 4*(rtcpHdr&0xFFFF); // doesn't count hdr | 
|---|
| 546 | ADVANCE(4); // skip over the header | 
|---|
| 547 | if (length > packetSize) break; | 
|---|
| 548 |  | 
|---|
| 549 | // Assume that each RTCP subpacket begins with a 4-byte SSRC: | 
|---|
| 550 | if (length < 4) break; length -= 4; | 
|---|
| 551 | reportSenderSSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 552 | #ifdef HACK_FOR_CHROME_WEBRTC_BUG | 
|---|
| 553 | if (reportSenderSSRC == 0x00000001 && pt == RTCP_PT_RR) { | 
|---|
| 554 | // Chrome (and Opera) WebRTC receivers have a bug that causes them to always send | 
|---|
| 555 | // SSRC 1 in their "RR"s.  To work around this (to help us distinguish between different | 
|---|
| 556 | // receivers), we use a fake SSRC in this case consisting of the IP address, XORed with | 
|---|
| 557 | // the port number: | 
|---|
| 558 | reportSenderSSRC = fromAddressAndPort.sin_addr.s_addr^fromAddressAndPort.sin_port; | 
|---|
| 559 | } | 
|---|
| 560 | #endif | 
|---|
| 561 |  | 
|---|
| 562 | Boolean subPacketOK = False; | 
|---|
| 563 | switch (pt) { | 
|---|
| 564 | case RTCP_PT_SR: { | 
|---|
| 565 | #ifdef DEBUG | 
|---|
| 566 | fprintf(stderr, "SR\n"); | 
|---|
| 567 | #endif | 
|---|
| 568 | if (length < 20) break; length -= 20; | 
|---|
| 569 |  | 
|---|
| 570 | // Extract the NTP timestamp, and note this: | 
|---|
| 571 | unsigned NTPmsw = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 572 | unsigned NTPlsw = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 573 | unsigned rtpTimestamp = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 574 | if (fSource != NULL) { | 
|---|
| 575 | RTPReceptionStatsDB& receptionStats | 
|---|
| 576 | = fSource->receptionStatsDB(); | 
|---|
| 577 | receptionStats.noteIncomingSR(reportSenderSSRC, | 
|---|
| 578 | NTPmsw, NTPlsw, rtpTimestamp); | 
|---|
| 579 | } | 
|---|
| 580 | ADVANCE(8); // skip over packet count, octet count | 
|---|
| 581 |  | 
|---|
| 582 | // If a 'SR handler' was set, call it now: | 
|---|
| 583 | if (fSRHandlerTask != NULL) (*fSRHandlerTask)(fSRHandlerClientData); | 
|---|
| 584 |  | 
|---|
| 585 | // The rest of the SR is handled like a RR (so, no "break;" here) | 
|---|
| 586 | } | 
|---|
| 587 | case RTCP_PT_RR: { | 
|---|
| 588 | #ifdef DEBUG | 
|---|
| 589 | fprintf(stderr, "RR\n"); | 
|---|
| 590 | #endif | 
|---|
| 591 | unsigned reportBlocksSize = rc*(6*4); | 
|---|
| 592 | if (length < reportBlocksSize) break; | 
|---|
| 593 | length -= reportBlocksSize; | 
|---|
| 594 |  | 
|---|
| 595 | if (fSink != NULL) { | 
|---|
| 596 | // Use this information to update stats about our transmissions: | 
|---|
| 597 | RTPTransmissionStatsDB& transmissionStats = fSink->transmissionStatsDB(); | 
|---|
| 598 | for (unsigned i = 0; i < rc; ++i) { | 
|---|
| 599 | unsigned  = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 600 | // We care only about reports about our own transmission, not others' | 
|---|
| 601 | if (senderSSRC == fSink->SSRC()) { | 
|---|
| 602 | unsigned lossStats = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 603 | unsigned highestReceived = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 604 | unsigned jitter = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 605 | unsigned timeLastSR = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 606 | unsigned timeSinceLastSR = ntohl(*(u_int32_t*)pkt); ADVANCE(4); | 
|---|
| 607 | transmissionStats.noteIncomingRR(reportSenderSSRC, fromAddressAndPort, | 
|---|
| 608 | lossStats, | 
|---|
| 609 | highestReceived, jitter, | 
|---|
| 610 | timeLastSR, timeSinceLastSR); | 
|---|
| 611 | } else { | 
|---|
| 612 | ADVANCE(4*5); | 
|---|
| 613 | } | 
|---|
| 614 | } | 
|---|
| 615 | } else { | 
|---|
| 616 | ADVANCE(reportBlocksSize); | 
|---|
| 617 | } | 
|---|
| 618 |  | 
|---|
| 619 | if (pt == RTCP_PT_RR) { // i.e., we didn't fall through from 'SR' | 
|---|
| 620 | noteArrivingRR(fromAddressAndPort, tcpSocketNum, tcpStreamChannelId); | 
|---|
| 621 | } | 
|---|
| 622 |  | 
|---|
| 623 | subPacketOK = True; | 
|---|
| 624 | typeOfPacket = PACKET_RTCP_REPORT; | 
|---|
| 625 | break; | 
|---|
| 626 | } | 
|---|
| 627 | case RTCP_PT_BYE: { | 
|---|
| 628 | #ifdef DEBUG | 
|---|
| 629 | fprintf(stderr, "BYE"); | 
|---|
| 630 | #endif | 
|---|
| 631 | // Check whether there was a 'reason for leaving': | 
|---|
| 632 | if (length > 0) { | 
|---|
| 633 | u_int8_t reasonLength = *pkt; | 
|---|
| 634 | if (reasonLength > length-1) { | 
|---|
| 635 | // The 'reason' length field is too large! | 
|---|
| 636 | #ifdef DEBUG | 
|---|
| 637 | fprintf(stderr, "\nError: The 'reason' length %d is too large (it should be <= %d)\n", | 
|---|
| 638 | reasonLength, length-1); | 
|---|
| 639 | #endif | 
|---|
| 640 | reasonLength = length-1; | 
|---|
| 641 | } | 
|---|
| 642 | reason = new char[reasonLength + 1]; | 
|---|
| 643 | for (unsigned i = 0; i < reasonLength; ++i) { | 
|---|
| 644 | reason[i] = pkt[1+i]; | 
|---|
| 645 | } | 
|---|
| 646 | reason[reasonLength] = '\0'; | 
|---|
| 647 | #ifdef DEBUG | 
|---|
| 648 | fprintf(stderr, " (reason:%s)", reason); | 
|---|
| 649 | #endif | 
|---|
| 650 | } | 
|---|
| 651 | #ifdef DEBUG | 
|---|
| 652 | fprintf(stderr, "\n"); | 
|---|
| 653 | #endif | 
|---|
| 654 | // If a 'BYE handler' was set, arrange for it to be called at the end of this routine. | 
|---|
| 655 | // (Note: We don't call it immediately, in case it happens to cause "this" to be deleted.) | 
|---|
| 656 | if ((fByeHandlerTask != NULL || fByeWithReasonHandlerTask != NULL) | 
|---|
| 657 | && (!fByeHandleActiveParticipantsOnly | 
|---|
| 658 | || (fSource != NULL | 
|---|
| 659 | && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL) | 
|---|
| 660 | || (fSink != NULL | 
|---|
| 661 | && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) { | 
|---|
| 662 | callByeHandler = True; | 
|---|
| 663 | } | 
|---|
| 664 |  | 
|---|
| 665 | // We should really check for & handle >1 SSRCs being present ##### | 
|---|
| 666 |  | 
|---|
| 667 | subPacketOK = True; | 
|---|
| 668 | typeOfPacket = PACKET_BYE; | 
|---|
| 669 | break; | 
|---|
| 670 | } | 
|---|
| 671 | case RTCP_PT_APP: { | 
|---|
| 672 | u_int8_t& subtype = rc; // In "APP" packets, the "rc" field gets used as "subtype" | 
|---|
| 673 | #ifdef DEBUG | 
|---|
| 674 | fprintf(stderr, "APP (subtype 0x%02x)\n", subtype); | 
|---|
| 675 | #endif | 
|---|
| 676 | if (length < 4) { | 
|---|
| 677 | #ifdef DEBUG | 
|---|
| 678 | fprintf(stderr, "\tError: No \"name\" field!\n"); | 
|---|
| 679 | #endif | 
|---|
| 680 | break; | 
|---|
| 681 | } | 
|---|
| 682 | length -= 4; | 
|---|
| 683 | #ifdef DEBUG | 
|---|
| 684 | fprintf(stderr, "\tname:%c%c%c%c\n", pkt[0], pkt[1], pkt[2], pkt[3]); | 
|---|
| 685 | #endif | 
|---|
| 686 | u_int32_t nameBytes = (pkt[0]<<24)|(pkt[1]<<16)|(pkt[2]<<8)|(pkt[3]); | 
|---|
| 687 | ADVANCE(4); // skip over "name", to the 'application-dependent data' | 
|---|
| 688 | #ifdef DEBUG | 
|---|
| 689 | fprintf(stderr, "\tapplication-dependent data size: %d bytes\n", length); | 
|---|
| 690 | #endif | 
|---|
| 691 |  | 
|---|
| 692 | // If an 'APP' packet handler was set, call it now: | 
|---|
| 693 | if (fAppHandlerTask != NULL) { | 
|---|
| 694 | (*fAppHandlerTask)(fAppHandlerClientData, subtype, nameBytes, pkt, length); | 
|---|
| 695 | } | 
|---|
| 696 | subPacketOK = True; | 
|---|
| 697 | typeOfPacket = PACKET_RTCP_APP; | 
|---|
| 698 | break; | 
|---|
| 699 | } | 
|---|
| 700 | // Other RTCP packet types that we don't yet handle: | 
|---|
| 701 | case RTCP_PT_SDES: { | 
|---|
| 702 | #ifdef DEBUG | 
|---|
| 703 | // 'Handle' SDES packets only in debugging code, by printing out the 'SDES items': | 
|---|
| 704 | fprintf(stderr, "SDES\n"); | 
|---|
| 705 |  | 
|---|
| 706 | // Process each 'chunk': | 
|---|
| 707 | Boolean chunkOK = False; | 
|---|
| 708 | ADVANCE(-4); length += 4; // hack so that we see the first SSRC/CSRC again | 
|---|
| 709 | while (length >= 8) { // A valid chunk must be at least 8 bytes long | 
|---|
| 710 | chunkOK = False; // until we learn otherwise | 
|---|
| 711 |  | 
|---|
| 712 | u_int32_t SSRC_CSRC = ntohl(*(u_int32_t*)pkt); ADVANCE(4); length -= 4; | 
|---|
| 713 | fprintf(stderr, "\tSSRC/CSRC: 0x%08x\n", SSRC_CSRC); | 
|---|
| 714 |  | 
|---|
| 715 | // Process each 'SDES item' in the chunk: | 
|---|
| 716 | u_int8_t itemType = *pkt; ADVANCE(1); --length; | 
|---|
| 717 | while (itemType != 0) { | 
|---|
| 718 | unsigned itemLen = *pkt; ADVANCE(1); --length; | 
|---|
| 719 | // Make sure "itemLen" allows for at least 1 zero byte at the end of the chunk: | 
|---|
| 720 | if (itemLen + 1 > length || pkt[itemLen] != 0) break; | 
|---|
| 721 |  | 
|---|
| 722 | fprintf(stderr, "\t\t%s:%s\n", | 
|---|
| 723 | itemType == 1 ? "CNAME": | 
|---|
| 724 | itemType == 2 ? "NAME": | 
|---|
| 725 | itemType == 3 ? "EMAIL": | 
|---|
| 726 | itemType == 4 ? "PHONE": | 
|---|
| 727 | itemType == 5 ? "LOC": | 
|---|
| 728 | itemType == 6 ? "TOOL": | 
|---|
| 729 | itemType == 7 ? "NOTE": | 
|---|
| 730 | itemType == 8 ? "PRIV": | 
|---|
| 731 | "(unknown)", | 
|---|
| 732 | itemType < 8 ? (char*)pkt // hack, because we know it's '\0'-terminated | 
|---|
| 733 | : "???"/* don't try to print out PRIV or unknown items */); | 
|---|
| 734 | ADVANCE(itemLen); length -= itemLen; | 
|---|
| 735 |  | 
|---|
| 736 | itemType = *pkt; ADVANCE(1); --length; | 
|---|
| 737 | } | 
|---|
| 738 | if (itemType != 0) break; // bad 'SDES item' | 
|---|
| 739 |  | 
|---|
| 740 | // Thus, itemType == 0.  This zero 'type' marks the end of the list of SDES items. | 
|---|
| 741 | // Skip over remaining zero padding bytes, so that this chunk ends on a 4-byte boundary: | 
|---|
| 742 | while (length%4 > 0 && *pkt == 0) { ADVANCE(1); --length; } | 
|---|
| 743 | if (length%4 > 0) break; // Bad (non-zero) padding byte | 
|---|
| 744 |  | 
|---|
| 745 | chunkOK = True; | 
|---|
| 746 | } | 
|---|
| 747 | if (!chunkOK || length > 0) break; // bad chunk, or not enough bytes for the last chunk | 
|---|
| 748 | #endif | 
|---|
| 749 | subPacketOK = True; | 
|---|
| 750 | break; | 
|---|
| 751 | } | 
|---|
| 752 | case RTCP_PT_RTPFB: { | 
|---|
| 753 | #ifdef DEBUG | 
|---|
| 754 | fprintf(stderr, "RTPFB(unhandled)\n"); | 
|---|
| 755 | #endif | 
|---|
| 756 | subPacketOK = True; | 
|---|
| 757 | break; | 
|---|
| 758 | } | 
|---|
| 759 | case RTCP_PT_PSFB: { | 
|---|
| 760 | #ifdef DEBUG | 
|---|
| 761 | fprintf(stderr, "PSFB(unhandled)\n"); | 
|---|
| 762 | // Temporary code to show "Receiver Estimated Maximum Bitrate" (REMB) feedback reports: | 
|---|
| 763 | //##### | 
|---|
| 764 | if (length >= 12 && pkt[4] == 'R' && pkt[5] == 'E' && pkt[6] == 'M' && pkt[7] == 'B') { | 
|---|
| 765 | u_int8_t exp = pkt[9]>>2; | 
|---|
| 766 | u_int32_t mantissa = ((pkt[9]&0x03)<<16)|(pkt[10]<<8)|pkt[11]; | 
|---|
| 767 | double remb = (double)mantissa; | 
|---|
| 768 | while (exp > 0) { | 
|---|
| 769 | remb *= 2.0; | 
|---|
| 770 | exp /= 2; | 
|---|
| 771 | } | 
|---|
| 772 | fprintf(stderr, "\tReceiver Estimated Max Bitrate (REMB): %g bps\n", remb); | 
|---|
| 773 | } | 
|---|
| 774 | #endif | 
|---|
| 775 | subPacketOK = True; | 
|---|
| 776 | break; | 
|---|
| 777 | } | 
|---|
| 778 | case RTCP_PT_XR: { | 
|---|
| 779 | #ifdef DEBUG | 
|---|
| 780 | fprintf(stderr, "XR(unhandled)\n"); | 
|---|
| 781 | #endif | 
|---|
| 782 | subPacketOK = True; | 
|---|
| 783 | break; | 
|---|
| 784 | } | 
|---|
| 785 | case RTCP_PT_AVB: { | 
|---|
| 786 | #ifdef DEBUG | 
|---|
| 787 | fprintf(stderr, "AVB(unhandled)\n"); | 
|---|
| 788 | #endif | 
|---|
| 789 | subPacketOK = True; | 
|---|
| 790 | break; | 
|---|
| 791 | } | 
|---|
| 792 | case RTCP_PT_RSI: { | 
|---|
| 793 | #ifdef DEBUG | 
|---|
| 794 | fprintf(stderr, "RSI(unhandled)\n"); | 
|---|
| 795 | #endif | 
|---|
| 796 | subPacketOK = True; | 
|---|
| 797 | break; | 
|---|
| 798 | } | 
|---|
| 799 | case RTCP_PT_TOKEN: { | 
|---|
| 800 | #ifdef DEBUG | 
|---|
| 801 | fprintf(stderr, "TOKEN(unhandled)\n"); | 
|---|
| 802 | #endif | 
|---|
| 803 | subPacketOK = True; | 
|---|
| 804 | break; | 
|---|
| 805 | } | 
|---|
| 806 | case RTCP_PT_IDMS: { | 
|---|
| 807 | #ifdef DEBUG | 
|---|
| 808 | fprintf(stderr, "IDMS(unhandled)\n"); | 
|---|
| 809 | #endif | 
|---|
| 810 | subPacketOK = True; | 
|---|
| 811 | break; | 
|---|
| 812 | } | 
|---|
| 813 | default: { | 
|---|
| 814 | #ifdef DEBUG | 
|---|
| 815 | fprintf(stderr, "UNKNOWN TYPE(0x%x)\n", pt); | 
|---|
| 816 | #endif | 
|---|
| 817 | subPacketOK = True; | 
|---|
| 818 | break; | 
|---|
| 819 | } | 
|---|
| 820 | } | 
|---|
| 821 | if (!subPacketOK) break; | 
|---|
| 822 |  | 
|---|
| 823 | // need to check for (& handle) SSRC collision! ##### | 
|---|
| 824 |  | 
|---|
| 825 | #ifdef DEBUG | 
|---|
| 826 | fprintf(stderr, "validated RTCP subpacket: rc:%d, pt:%d, bytes remaining:%d, report sender SSRC:0x%08x\n", rc, pt, length, reportSenderSSRC); | 
|---|
| 827 | #endif | 
|---|
| 828 |  | 
|---|
| 829 | // Skip over any remaining bytes in this subpacket: | 
|---|
| 830 | ADVANCE(length); | 
|---|
| 831 |  | 
|---|
| 832 | // Check whether another RTCP 'subpacket' follows: | 
|---|
| 833 | if (packetSize == 0) { | 
|---|
| 834 | packetOK = True; | 
|---|
| 835 | break; | 
|---|
| 836 | } else if (packetSize < 4) { | 
|---|
| 837 | #ifdef DEBUG | 
|---|
| 838 | fprintf(stderr, "extraneous %d bytes at end of RTCP packet!\n", packetSize); | 
|---|
| 839 | #endif | 
|---|
| 840 | break; | 
|---|
| 841 | } | 
|---|
| 842 | rtcpHdr = ntohl(*(u_int32_t*)pkt); | 
|---|
| 843 | if ((rtcpHdr & 0xC0000000) != 0x80000000) { | 
|---|
| 844 | #ifdef DEBUG | 
|---|
| 845 | fprintf(stderr, "bad RTCP subpacket: header 0x%08x\n", rtcpHdr); | 
|---|
| 846 | #endif | 
|---|
| 847 | break; | 
|---|
| 848 | } | 
|---|
| 849 | } | 
|---|
| 850 |  | 
|---|
| 851 | if (!packetOK) { | 
|---|
| 852 | #ifdef DEBUG | 
|---|
| 853 | fprintf(stderr, "rejected bad RTCP subpacket: header 0x%08x\n", rtcpHdr); | 
|---|
| 854 | #endif | 
|---|
| 855 | break; | 
|---|
| 856 | } else { | 
|---|
| 857 | #ifdef DEBUG | 
|---|
| 858 | fprintf(stderr, "validated entire RTCP packet\n"); | 
|---|
| 859 | #endif | 
|---|
| 860 | } | 
|---|
| 861 |  | 
|---|
| 862 | onReceive(typeOfPacket, totPacketSize, reportSenderSSRC); | 
|---|
| 863 |  | 
|---|
| 864 | // Finally, if we need to call a "BYE" handler, do so now (in case it causes "this" to get deleted): | 
|---|
| 865 | if (callByeHandler) { | 
|---|
| 866 | if (fByeHandlerTask != NULL) { // call a BYE handler without including a 'reason' | 
|---|
| 867 | TaskFunc* byeHandler = fByeHandlerTask; | 
|---|
| 868 | fByeHandlerTask = NULL; // because we call the handler only once, by default | 
|---|
| 869 | (*byeHandler)(fByeHandlerClientData); | 
|---|
| 870 | } else if (fByeWithReasonHandlerTask != NULL) { // call a BYE handler that includes a 'reason' | 
|---|
| 871 | ByeWithReasonHandlerFunc* byeHandler = fByeWithReasonHandlerTask; | 
|---|
| 872 | fByeWithReasonHandlerTask = NULL; // because we call the handler only once, by default | 
|---|
| 873 | (*byeHandler)(fByeHandlerClientData, reason); | 
|---|
| 874 | // Note that the handler function is responsible for delete[]ing "reason" | 
|---|
| 875 | } | 
|---|
| 876 | } | 
|---|
| 877 | } while (0); | 
|---|
| 878 | } | 
|---|
| 879 |  | 
|---|
| 880 | void RTCPInstance::onReceive(int typeOfPacket, int totPacketSize, u_int32_t ssrc) { | 
|---|
| 881 | fTypeOfPacket = typeOfPacket; | 
|---|
| 882 | fLastReceivedSize = totPacketSize; | 
|---|
| 883 | fLastReceivedSSRC = ssrc; | 
|---|
| 884 |  | 
|---|
| 885 | int members = (int)numMembers(); | 
|---|
| 886 | int senders = (fSink != NULL) ? 1 : 0; | 
|---|
| 887 |  | 
|---|
| 888 | OnReceive(this, // p | 
|---|
| 889 | this, // e | 
|---|
| 890 | &members, // members | 
|---|
| 891 | &fPrevNumMembers, // pmembers | 
|---|
| 892 | &senders, // senders | 
|---|
| 893 | &fAveRTCPSize, // avg_rtcp_size | 
|---|
| 894 | &fPrevReportTime, // tp | 
|---|
| 895 | dTimeNow(), // tc | 
|---|
| 896 | fNextReportTime); | 
|---|
| 897 | } | 
|---|
| 898 |  | 
|---|
| 899 | void RTCPInstance::sendReport() { | 
|---|
| 900 | #ifdef DEBUG | 
|---|
| 901 | fprintf(stderr, "sending REPORT\n"); | 
|---|
| 902 | #endif | 
|---|
| 903 | // Begin by including a SR and/or RR report: | 
|---|
| 904 | if (!addReport()) return; | 
|---|
| 905 |  | 
|---|
| 906 | // Then, include a SDES: | 
|---|
| 907 | addSDES(); | 
|---|
| 908 |  | 
|---|
| 909 | // Send the report: | 
|---|
| 910 | sendBuiltPacket(); | 
|---|
| 911 |  | 
|---|
| 912 | // Periodically clean out old members from our SSRC membership database: | 
|---|
| 913 | const unsigned membershipReapPeriod = 5; | 
|---|
| 914 | if ((++fOutgoingReportCount) % membershipReapPeriod == 0) { | 
|---|
| 915 | unsigned threshold = fOutgoingReportCount - membershipReapPeriod; | 
|---|
| 916 | fKnownMembers->reapOldMembers(threshold); | 
|---|
| 917 | } | 
|---|
| 918 | } | 
|---|
| 919 |  | 
|---|
| 920 | void RTCPInstance::sendBYE(char const* reason) { | 
|---|
| 921 | #ifdef DEBUG | 
|---|
| 922 | if (reason != NULL) { | 
|---|
| 923 | fprintf(stderr, "sending BYE (reason:%s)\n", reason); | 
|---|
| 924 | } else { | 
|---|
| 925 | fprintf(stderr, "sending BYE\n"); | 
|---|
| 926 | } | 
|---|
| 927 | #endif | 
|---|
| 928 | // The packet must begin with a SR and/or RR report: | 
|---|
| 929 | (void)addReport(True); | 
|---|
| 930 |  | 
|---|
| 931 | addBYE(reason); | 
|---|
| 932 | sendBuiltPacket(); | 
|---|
| 933 | } | 
|---|
| 934 |  | 
|---|
| 935 | void RTCPInstance::sendBuiltPacket() { | 
|---|
| 936 | #ifdef DEBUG | 
|---|
| 937 | fprintf(stderr, "sending RTCP packet\n"); | 
|---|
| 938 | unsigned char* p = fOutBuf->packet(); | 
|---|
| 939 | for (unsigned i = 0; i < fOutBuf->curPacketSize(); ++i) { | 
|---|
| 940 | if (i%4 == 0) fprintf(stderr, " "); | 
|---|
| 941 | fprintf(stderr, "%02x", p[i]); | 
|---|
| 942 | } | 
|---|
| 943 | fprintf(stderr, "\n"); | 
|---|
| 944 | #endif | 
|---|
| 945 | unsigned reportSize = fOutBuf->curPacketSize(); | 
|---|
| 946 | fRTCPInterface.sendPacket(fOutBuf->packet(), reportSize); | 
|---|
| 947 | fOutBuf->resetOffset(); | 
|---|
| 948 |  | 
|---|
| 949 | fLastSentSize = IP_UDP_HDR_SIZE + reportSize; | 
|---|
| 950 | fHaveJustSentPacket = True; | 
|---|
| 951 | fLastPacketSentSize = reportSize; | 
|---|
| 952 | } | 
|---|
| 953 |  | 
|---|
| 954 | int RTCPInstance::checkNewSSRC() { | 
|---|
| 955 | return fKnownMembers->noteMembership(fLastReceivedSSRC, | 
|---|
| 956 | fOutgoingReportCount); | 
|---|
| 957 | } | 
|---|
| 958 |  | 
|---|
| 959 | void RTCPInstance::removeLastReceivedSSRC() { | 
|---|
| 960 | removeSSRC(fLastReceivedSSRC, False/*keep stats around*/); | 
|---|
| 961 | } | 
|---|
| 962 |  | 
|---|
| 963 | void RTCPInstance::removeSSRC(u_int32_t ssrc, Boolean alsoRemoveStats) { | 
|---|
| 964 | fKnownMembers->remove(ssrc); | 
|---|
| 965 |  | 
|---|
| 966 | if (alsoRemoveStats) { | 
|---|
| 967 | // Also, remove records of this SSRC from any reception or transmission stats | 
|---|
| 968 | if (fSource != NULL) fSource->receptionStatsDB().removeRecord(ssrc); | 
|---|
| 969 | if (fSink != NULL) fSink->transmissionStatsDB().removeRecord(ssrc); | 
|---|
| 970 | } | 
|---|
| 971 | } | 
|---|
| 972 |  | 
|---|
| 973 | void RTCPInstance::onExpire(RTCPInstance* instance) { | 
|---|
| 974 | instance->onExpire1(); | 
|---|
| 975 | } | 
|---|
| 976 |  | 
|---|
| 977 | // Member functions to build specific kinds of report: | 
|---|
| 978 |  | 
|---|
| 979 | Boolean RTCPInstance::addReport(Boolean alwaysAdd) { | 
|---|
| 980 | // Include a SR or a RR, depending on whether we have an associated sink or source: | 
|---|
| 981 | if (fSink != NULL) { | 
|---|
| 982 | if (!alwaysAdd) { | 
|---|
| 983 | if (!fSink->enableRTCPReports()) return False; | 
|---|
| 984 |  | 
|---|
| 985 | // Hack: Don't send a SR during those (brief) times when the timestamp of the | 
|---|
| 986 | // next outgoing RTP packet has been preset, to ensure that that timestamp gets | 
|---|
| 987 | // used for that outgoing packet. (David Bertrand, 2006.07.18) | 
|---|
| 988 | if (fSink->nextTimestampHasBeenPreset()) return False; | 
|---|
| 989 | } | 
|---|
| 990 |  | 
|---|
| 991 | addSR(); | 
|---|
| 992 | } | 
|---|
| 993 | if (fSource != NULL) { | 
|---|
| 994 | if (!alwaysAdd) { | 
|---|
| 995 | if (!fSource->enableRTCPReports()) return False; | 
|---|
| 996 | } | 
|---|
| 997 |  | 
|---|
| 998 | addRR(); | 
|---|
| 999 | } | 
|---|
| 1000 |  | 
|---|
| 1001 | return True; | 
|---|
| 1002 | } | 
|---|
| 1003 |  | 
|---|
| 1004 | void RTCPInstance::addSR() { | 
|---|
| 1005 | // ASSERT: fSink != NULL | 
|---|
| 1006 |  | 
|---|
| 1007 | enqueueCommonReportPrefix(RTCP_PT_SR, fSink->SSRC(), | 
|---|
| 1008 | 5 /* extra words in a SR */); | 
|---|
| 1009 |  | 
|---|
| 1010 | // Now, add the 'sender info' for our sink | 
|---|
| 1011 |  | 
|---|
| 1012 | // Insert the NTP and RTP timestamps for the 'wallclock time': | 
|---|
| 1013 | struct timeval timeNow; | 
|---|
| 1014 | gettimeofday(&timeNow, NULL); | 
|---|
| 1015 | fOutBuf->enqueueWord(timeNow.tv_sec + 0x83AA7E80); | 
|---|
| 1016 | // NTP timestamp most-significant word (1970 epoch -> 1900 epoch) | 
|---|
| 1017 | double fractionalPart = (timeNow.tv_usec/15625.0)*0x04000000; // 2^32/10^6 | 
|---|
| 1018 | fOutBuf->enqueueWord((unsigned)(fractionalPart+0.5)); | 
|---|
| 1019 | // NTP timestamp least-significant word | 
|---|
| 1020 | unsigned rtpTimestamp = fSink->convertToRTPTimestamp(timeNow); | 
|---|
| 1021 | fOutBuf->enqueueWord(rtpTimestamp); // RTP ts | 
|---|
| 1022 |  | 
|---|
| 1023 | // Insert the packet and byte counts: | 
|---|
| 1024 | fOutBuf->enqueueWord(fSink->packetCount()); | 
|---|
| 1025 | fOutBuf->enqueueWord(fSink->octetCount()); | 
|---|
| 1026 |  | 
|---|
| 1027 | enqueueCommonReportSuffix(); | 
|---|
| 1028 | } | 
|---|
| 1029 |  | 
|---|
| 1030 | void RTCPInstance::addRR() { | 
|---|
| 1031 | // ASSERT: fSource != NULL | 
|---|
| 1032 |  | 
|---|
| 1033 | enqueueCommonReportPrefix(RTCP_PT_RR, fSource->SSRC()); | 
|---|
| 1034 | enqueueCommonReportSuffix(); | 
|---|
| 1035 | } | 
|---|
| 1036 |  | 
|---|
| 1037 | void RTCPInstance::enqueueCommonReportPrefix(unsigned char packetType, | 
|---|
| 1038 | u_int32_t SSRC, | 
|---|
| 1039 | unsigned ) { | 
|---|
| 1040 | unsigned numReportingSources; | 
|---|
| 1041 | if (fSource == NULL) { | 
|---|
| 1042 | numReportingSources = 0; // we don't receive anything | 
|---|
| 1043 | } else { | 
|---|
| 1044 | RTPReceptionStatsDB& allReceptionStats | 
|---|
| 1045 | = fSource->receptionStatsDB(); | 
|---|
| 1046 | numReportingSources = allReceptionStats.numActiveSourcesSinceLastReset(); | 
|---|
| 1047 | // This must be <32, to fit in 5 bits: | 
|---|
| 1048 | if (numReportingSources >= 32) { numReportingSources = 32; } | 
|---|
| 1049 | // Later: support adding more reports to handle >32 sources (unlikely)##### | 
|---|
| 1050 | } | 
|---|
| 1051 |  | 
|---|
| 1052 | unsigned rtcpHdr = 0x80000000; // version 2, no padding | 
|---|
| 1053 | rtcpHdr |= (numReportingSources<<24); | 
|---|
| 1054 | rtcpHdr |= (packetType<<16); | 
|---|
| 1055 | rtcpHdr |= (1 + numExtraWords + 6*numReportingSources); | 
|---|
| 1056 | // each report block is 6 32-bit words long | 
|---|
| 1057 | fOutBuf->enqueueWord(rtcpHdr); | 
|---|
| 1058 |  | 
|---|
| 1059 | fOutBuf->enqueueWord(SSRC); | 
|---|
| 1060 | } | 
|---|
| 1061 |  | 
|---|
| 1062 | void RTCPInstance::enqueueCommonReportSuffix() { | 
|---|
| 1063 | // Output the report blocks for each source: | 
|---|
| 1064 | if (fSource != NULL) { | 
|---|
| 1065 | RTPReceptionStatsDB& allReceptionStats | 
|---|
| 1066 | = fSource->receptionStatsDB(); | 
|---|
| 1067 |  | 
|---|
| 1068 | RTPReceptionStatsDB::Iterator iterator(allReceptionStats); | 
|---|
| 1069 | while (1) { | 
|---|
| 1070 | RTPReceptionStats* receptionStats = iterator.next(); | 
|---|
| 1071 | if (receptionStats == NULL) break; | 
|---|
| 1072 | enqueueReportBlock(receptionStats); | 
|---|
| 1073 | } | 
|---|
| 1074 |  | 
|---|
| 1075 | allReceptionStats.reset(); // because we have just generated a report | 
|---|
| 1076 | } | 
|---|
| 1077 | } | 
|---|
| 1078 |  | 
|---|
| 1079 | void | 
|---|
| 1080 | RTCPInstance::enqueueReportBlock(RTPReceptionStats* stats) { | 
|---|
| 1081 | fOutBuf->enqueueWord(stats->SSRC()); | 
|---|
| 1082 |  | 
|---|
| 1083 | unsigned highestExtSeqNumReceived = stats->highestExtSeqNumReceived(); | 
|---|
| 1084 |  | 
|---|
| 1085 | unsigned totNumExpected | 
|---|
| 1086 | = highestExtSeqNumReceived - stats->baseExtSeqNumReceived(); | 
|---|
| 1087 | int totNumLost = totNumExpected - stats->totNumPacketsReceived(); | 
|---|
| 1088 | // 'Clamp' this loss number to a 24-bit signed value: | 
|---|
| 1089 | if (totNumLost > 0x007FFFFF) { | 
|---|
| 1090 | totNumLost = 0x007FFFFF; | 
|---|
| 1091 | } else if (totNumLost < 0) { | 
|---|
| 1092 | if (totNumLost < -0x00800000) totNumLost = 0x00800000; // unlikely, but... | 
|---|
| 1093 | totNumLost &= 0x00FFFFFF; | 
|---|
| 1094 | } | 
|---|
| 1095 |  | 
|---|
| 1096 | unsigned numExpectedSinceLastReset | 
|---|
| 1097 | = highestExtSeqNumReceived - stats->lastResetExtSeqNumReceived(); | 
|---|
| 1098 | int numLostSinceLastReset | 
|---|
| 1099 | = numExpectedSinceLastReset - stats->numPacketsReceivedSinceLastReset(); | 
|---|
| 1100 | unsigned char lossFraction; | 
|---|
| 1101 | if (numExpectedSinceLastReset == 0 || numLostSinceLastReset < 0) { | 
|---|
| 1102 | lossFraction = 0; | 
|---|
| 1103 | } else { | 
|---|
| 1104 | lossFraction = (unsigned char) | 
|---|
| 1105 | ((numLostSinceLastReset << 8) / numExpectedSinceLastReset); | 
|---|
| 1106 | } | 
|---|
| 1107 |  | 
|---|
| 1108 | fOutBuf->enqueueWord((lossFraction<<24) | totNumLost); | 
|---|
| 1109 | fOutBuf->enqueueWord(highestExtSeqNumReceived); | 
|---|
| 1110 |  | 
|---|
| 1111 | fOutBuf->enqueueWord(stats->jitter()); | 
|---|
| 1112 |  | 
|---|
| 1113 | unsigned NTPmsw = stats->lastReceivedSR_NTPmsw(); | 
|---|
| 1114 | unsigned NTPlsw = stats->lastReceivedSR_NTPlsw(); | 
|---|
| 1115 | unsigned LSR = ((NTPmsw&0xFFFF)<<16)|(NTPlsw>>16); // middle 32 bits | 
|---|
| 1116 | fOutBuf->enqueueWord(LSR); | 
|---|
| 1117 |  | 
|---|
| 1118 | // Figure out how long has elapsed since the last SR rcvd from this src: | 
|---|
| 1119 | struct timeval const& LSRtime = stats->lastReceivedSR_time(); // "last SR" | 
|---|
| 1120 | struct timeval timeNow, timeSinceLSR; | 
|---|
| 1121 | gettimeofday(&timeNow, NULL); | 
|---|
| 1122 | if (timeNow.tv_usec < LSRtime.tv_usec) { | 
|---|
| 1123 | timeNow.tv_usec += 1000000; | 
|---|
| 1124 | timeNow.tv_sec -= 1; | 
|---|
| 1125 | } | 
|---|
| 1126 | timeSinceLSR.tv_sec = timeNow.tv_sec - LSRtime.tv_sec; | 
|---|
| 1127 | timeSinceLSR.tv_usec = timeNow.tv_usec - LSRtime.tv_usec; | 
|---|
| 1128 | // The enqueued time is in units of 1/65536 seconds. | 
|---|
| 1129 | // (Note that 65536/1000000 == 1024/15625) | 
|---|
| 1130 | unsigned DLSR; | 
|---|
| 1131 | if (LSR == 0) { | 
|---|
| 1132 | DLSR = 0; | 
|---|
| 1133 | } else { | 
|---|
| 1134 | DLSR = (timeSinceLSR.tv_sec<<16) | 
|---|
| 1135 | | ( (((timeSinceLSR.tv_usec<<11)+15625)/31250) & 0xFFFF); | 
|---|
| 1136 | } | 
|---|
| 1137 | fOutBuf->enqueueWord(DLSR); | 
|---|
| 1138 | } | 
|---|
| 1139 |  | 
|---|
| 1140 | void RTCPInstance::addSDES() { | 
|---|
| 1141 | // For now we support only the CNAME item; later support more ##### | 
|---|
| 1142 |  | 
|---|
| 1143 | // Begin by figuring out the size of the entire SDES report: | 
|---|
| 1144 | unsigned numBytes = 4; | 
|---|
| 1145 | // counts the SSRC, but not the header; it'll get subtracted out | 
|---|
| 1146 | numBytes += fCNAME.totalSize(); // includes id and length | 
|---|
| 1147 | numBytes += 1; // the special END item | 
|---|
| 1148 |  | 
|---|
| 1149 | unsigned num4ByteWords = (numBytes + 3)/4; | 
|---|
| 1150 |  | 
|---|
| 1151 | unsigned rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC chunk | 
|---|
| 1152 | rtcpHdr |= (RTCP_PT_SDES<<16); | 
|---|
| 1153 | rtcpHdr |= num4ByteWords; | 
|---|
| 1154 | fOutBuf->enqueueWord(rtcpHdr); | 
|---|
| 1155 |  | 
|---|
| 1156 | if (fSource != NULL) { | 
|---|
| 1157 | fOutBuf->enqueueWord(fSource->SSRC()); | 
|---|
| 1158 | } else if (fSink != NULL) { | 
|---|
| 1159 | fOutBuf->enqueueWord(fSink->SSRC()); | 
|---|
| 1160 | } | 
|---|
| 1161 |  | 
|---|
| 1162 | // Add the CNAME: | 
|---|
| 1163 | fOutBuf->enqueue(fCNAME.data(), fCNAME.totalSize()); | 
|---|
| 1164 |  | 
|---|
| 1165 | // Add the 'END' item (i.e., a zero byte), plus any more needed to pad: | 
|---|
| 1166 | unsigned numPaddingBytesNeeded = 4 - (fOutBuf->curPacketSize() % 4); | 
|---|
| 1167 | unsigned char const zero = '\0'; | 
|---|
| 1168 | while (numPaddingBytesNeeded-- > 0) fOutBuf->enqueue(&zero, 1); | 
|---|
| 1169 | } | 
|---|
| 1170 |  | 
|---|
| 1171 | void RTCPInstance::addBYE(char const* reason) { | 
|---|
| 1172 | u_int32_t rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC | 
|---|
| 1173 | rtcpHdr |= (RTCP_PT_BYE<<16); | 
|---|
| 1174 | u_int16_t num32BitWords = 2; // by default, two 32-bit words total (i.e., with 1 SSRC) | 
|---|
| 1175 | u_int8_t reasonLength8Bits = 0; // by default | 
|---|
| 1176 | if (reason != NULL) { | 
|---|
| 1177 | // We need to add more 32-bit words for the 'length+reason': | 
|---|
| 1178 | unsigned const reasonLength = strlen(reason); | 
|---|
| 1179 | reasonLength8Bits = reasonLength < 0xFF ? (u_int8_t)reasonLength : 0xFF; | 
|---|
| 1180 | unsigned  = ((1/*reason length field*/+reasonLength8Bits)+3)/4; | 
|---|
| 1181 |  | 
|---|
| 1182 | num32BitWords += numExtraWords; | 
|---|
| 1183 | } | 
|---|
| 1184 | rtcpHdr |= (num32BitWords-1); // length field | 
|---|
| 1185 | fOutBuf->enqueueWord(rtcpHdr); | 
|---|
| 1186 |  | 
|---|
| 1187 | if (fSource != NULL) { | 
|---|
| 1188 | fOutBuf->enqueueWord(fSource->SSRC()); | 
|---|
| 1189 | } else if (fSink != NULL) { | 
|---|
| 1190 | fOutBuf->enqueueWord(fSink->SSRC()); | 
|---|
| 1191 | } | 
|---|
| 1192 |  | 
|---|
| 1193 | num32BitWords -= 2; // ASSERT: num32BitWords >= 0 | 
|---|
| 1194 | if (num32BitWords > 0) { | 
|---|
| 1195 | // Add a length+'reason for leaving': | 
|---|
| 1196 | // First word: | 
|---|
| 1197 | u_int32_t lengthPlusFirst3ReasonBytes = reasonLength8Bits<<24; | 
|---|
| 1198 | unsigned index = 0; | 
|---|
| 1199 | if (reasonLength8Bits > index) lengthPlusFirst3ReasonBytes |= ((u_int8_t)reason[index++])<<16; | 
|---|
| 1200 | if (reasonLength8Bits > index) lengthPlusFirst3ReasonBytes |= ((u_int8_t)reason[index++])<<8; | 
|---|
| 1201 | if (reasonLength8Bits > index) lengthPlusFirst3ReasonBytes |= (u_int8_t)reason[index++]; | 
|---|
| 1202 | fOutBuf->enqueueWord(lengthPlusFirst3ReasonBytes); | 
|---|
| 1203 |  | 
|---|
| 1204 | // Any subsequent words: | 
|---|
| 1205 | if (reasonLength8Bits > 3) { | 
|---|
| 1206 | // ASSERT: num32BitWords > 1 | 
|---|
| 1207 | while (--num32BitWords > 0) { | 
|---|
| 1208 | u_int32_t fourMoreReasonBytes = 0; | 
|---|
| 1209 | if (reasonLength8Bits > index) fourMoreReasonBytes |= ((u_int8_t)reason[index++])<<24; | 
|---|
| 1210 | if (reasonLength8Bits > index) fourMoreReasonBytes |= ((u_int8_t)reason[index++])<<16; | 
|---|
| 1211 | if (reasonLength8Bits > index) fourMoreReasonBytes |= ((u_int8_t)reason[index++])<<8; | 
|---|
| 1212 | if (reasonLength8Bits > index) fourMoreReasonBytes |= (u_int8_t)reason[index++]; | 
|---|
| 1213 | fOutBuf->enqueueWord(fourMoreReasonBytes); | 
|---|
| 1214 | } | 
|---|
| 1215 | } | 
|---|
| 1216 | } | 
|---|
| 1217 | } | 
|---|
| 1218 |  | 
|---|
| 1219 | void RTCPInstance::schedule(double nextTime) { | 
|---|
| 1220 | fNextReportTime = nextTime; | 
|---|
| 1221 |  | 
|---|
| 1222 | double secondsToDelay = nextTime - dTimeNow(); | 
|---|
| 1223 | if (secondsToDelay < 0) secondsToDelay = 0; | 
|---|
| 1224 | #ifdef DEBUG | 
|---|
| 1225 | fprintf(stderr, "schedule(%f->%f)\n", secondsToDelay, nextTime); | 
|---|
| 1226 | #endif | 
|---|
| 1227 | int64_t usToGo = (int64_t)(secondsToDelay * 1000000); | 
|---|
| 1228 | nextTask() = envir().taskScheduler().scheduleDelayedTask(usToGo, | 
|---|
| 1229 | (TaskFunc*)RTCPInstance::onExpire, this); | 
|---|
| 1230 | } | 
|---|
| 1231 |  | 
|---|
| 1232 | void RTCPInstance::reschedule(double nextTime) { | 
|---|
| 1233 | envir().taskScheduler().unscheduleDelayedTask(nextTask()); | 
|---|
| 1234 | schedule(nextTime); | 
|---|
| 1235 | } | 
|---|
| 1236 |  | 
|---|
| 1237 | void RTCPInstance::onExpire1() { | 
|---|
| 1238 | nextTask() = NULL; | 
|---|
| 1239 |  | 
|---|
| 1240 | // Note: fTotSessionBW is kbits per second | 
|---|
| 1241 | double rtcpBW = 0.05*fTotSessionBW*1024/8; // -> bytes per second | 
|---|
| 1242 |  | 
|---|
| 1243 | OnExpire(this, // event | 
|---|
| 1244 | numMembers(), // members | 
|---|
| 1245 | (fSink != NULL) ? 1 : 0, // senders | 
|---|
| 1246 | rtcpBW, // rtcp_bw | 
|---|
| 1247 | (fSink != NULL) ? 1 : 0, // we_sent | 
|---|
| 1248 | &fAveRTCPSize, // ave_rtcp_size | 
|---|
| 1249 | &fIsInitial, // initial | 
|---|
| 1250 | dTimeNow(), // tc | 
|---|
| 1251 | &fPrevReportTime, // tp | 
|---|
| 1252 | &fPrevNumMembers // pmembers | 
|---|
| 1253 | ); | 
|---|
| 1254 | } | 
|---|
| 1255 |  | 
|---|
| 1256 | ////////// SDESItem ////////// | 
|---|
| 1257 |  | 
|---|
| 1258 | SDESItem::SDESItem(unsigned char tag, unsigned char const* value) { | 
|---|
| 1259 | unsigned length = strlen((char const*)value); | 
|---|
| 1260 | if (length > 0xFF) length = 0xFF; // maximum data length for a SDES item | 
|---|
| 1261 |  | 
|---|
| 1262 | fData[0] = tag; | 
|---|
| 1263 | fData[1] = (unsigned char)length; | 
|---|
| 1264 | memmove(&fData[2], value, length); | 
|---|
| 1265 | } | 
|---|
| 1266 |  | 
|---|
| 1267 | unsigned SDESItem::totalSize() const { | 
|---|
| 1268 | return 2 + (unsigned)fData[1]; | 
|---|
| 1269 | } | 
|---|
| 1270 |  | 
|---|
| 1271 |  | 
|---|
| 1272 | ////////// Implementation of routines imported by the "rtcp_from_spec" C code | 
|---|
| 1273 |  | 
|---|
| 1274 | extern "C"void Schedule(double nextTime, event e) { | 
|---|
| 1275 | RTCPInstance* instance = (RTCPInstance*)e; | 
|---|
| 1276 | if (instance == NULL) return; | 
|---|
| 1277 |  | 
|---|
| 1278 | instance->schedule(nextTime); | 
|---|
| 1279 | } | 
|---|
| 1280 |  | 
|---|
| 1281 | extern "C"void Reschedule(double nextTime, event e) { | 
|---|
| 1282 | RTCPInstance* instance = (RTCPInstance*)e; | 
|---|
| 1283 | if (instance == NULL) return; | 
|---|
| 1284 |  | 
|---|
| 1285 | instance->reschedule(nextTime); | 
|---|
| 1286 | } | 
|---|
| 1287 |  | 
|---|
| 1288 | extern "C"void SendRTCPReport(event e) { | 
|---|
| 1289 | RTCPInstance* instance = (RTCPInstance*)e; | 
|---|
| 1290 | if (instance == NULL) return; | 
|---|
| 1291 |  | 
|---|
| 1292 | instance->sendReport(); | 
|---|
| 1293 | } | 
|---|
| 1294 |  | 
|---|
| 1295 | extern "C"void SendBYEPacket(event e) { | 
|---|
| 1296 | RTCPInstance* instance = (RTCPInstance*)e; | 
|---|
| 1297 | if (instance == NULL) return; | 
|---|
| 1298 |  | 
|---|
| 1299 | instance->sendBYE(); | 
|---|
| 1300 | } | 
|---|
| 1301 |  | 
|---|
| 1302 | extern "C"int TypeOfEvent(event e) { | 
|---|
| 1303 | RTCPInstance* instance = (RTCPInstance*)e; | 
|---|
| 1304 | if (instance == NULL) return EVENT_UNKNOWN; | 
|---|
| 1305 |  | 
|---|
| 1306 | return instance->typeOfEvent(); | 
|---|
| 1307 | } | 
|---|
| 1308 |  | 
|---|
| 1309 | extern "C"int SentPacketSize(event e) { | 
|---|
| 1310 | RTCPInstance* instance = (RTCPInstance*)e; | 
|---|
| 1311 | if (instance == NULL) return 0; | 
|---|
| 1312 |  | 
|---|
| 1313 | return instance->sentPacketSize(); | 
|---|
| 1314 | } | 
|---|
| 1315 |  | 
|---|
| 1316 | extern "C"int PacketType(packet p) { | 
|---|
| 1317 | RTCPInstance* instance = (RTCPInstance*)p; | 
|---|
| 1318 | if (instance == NULL) return PACKET_UNKNOWN_TYPE; | 
|---|
| 1319 |  | 
|---|
| 1320 | return instance->packetType(); | 
|---|
| 1321 | } | 
|---|
| 1322 |  | 
|---|
| 1323 | extern "C"int ReceivedPacketSize(packet p) { | 
|---|
| 1324 | RTCPInstance* instance = (RTCPInstance*)p; | 
|---|
| 1325 | if (instance == NULL) return 0; | 
|---|
| 1326 |  | 
|---|
| 1327 | return instance->receivedPacketSize(); | 
|---|
| 1328 | } | 
|---|
| 1329 |  | 
|---|
| 1330 | extern "C"int NewMember(packet p) { | 
|---|
| 1331 | RTCPInstance* instance = (RTCPInstance*)p; | 
|---|
| 1332 | if (instance == NULL) return 0; | 
|---|
| 1333 |  | 
|---|
| 1334 | return instance->checkNewSSRC(); | 
|---|
| 1335 | } | 
|---|
| 1336 |  | 
|---|
| 1337 | extern "C"int NewSender(packet /*p*/) { | 
|---|
| 1338 | return 0; // we don't yet recognize senders other than ourselves ##### | 
|---|
| 1339 | } | 
|---|
| 1340 |  | 
|---|
| 1341 | extern "C"void AddMember(packet /*p*/) { | 
|---|
| 1342 | // Do nothing; all of the real work was done when NewMember() was called | 
|---|
| 1343 | } | 
|---|
| 1344 |  | 
|---|
| 1345 | extern "C"void AddSender(packet /*p*/) { | 
|---|
| 1346 | // we don't yet recognize senders other than ourselves ##### | 
|---|
| 1347 | } | 
|---|
| 1348 |  | 
|---|
| 1349 | extern "C"void RemoveMember(packet p) { | 
|---|
| 1350 | RTCPInstance* instance = (RTCPInstance*)p; | 
|---|
| 1351 | if (instance == NULL) return; | 
|---|
| 1352 |  | 
|---|
| 1353 | instance->removeLastReceivedSSRC(); | 
|---|
| 1354 | } | 
|---|
| 1355 |  | 
|---|
| 1356 | extern "C"void RemoveSender(packet /*p*/) { | 
|---|
| 1357 | // we don't yet recognize senders other than ourselves ##### | 
|---|
| 1358 | } | 
|---|
| 1359 |  | 
|---|
| 1360 | extern "C"double drand30() { | 
|---|
| 1361 | unsigned tmp = our_random()&0x3FFFFFFF; // a random 30-bit integer | 
|---|
| 1362 | return tmp/(double)(1024*1024*1024); | 
|---|
| 1363 | } | 
|---|
| 1364 |  | 
|---|