| 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 | // RTP Sources |
| 19 | // Implementation |
| 20 | |
| 21 | #include "RTPSource.hh" |
| 22 | #include "GroupsockHelper.hh" |
| 23 | |
| 24 | ////////// RTPSource ////////// |
| 25 | |
| 26 | Boolean RTPSource::lookupByName(UsageEnvironment& env, |
| 27 | char const* sourceName, |
| 28 | RTPSource*& resultSource) { |
| 29 | resultSource = NULL; // unless we succeed |
| 30 | |
| 31 | MediaSource* source; |
| 32 | if (!MediaSource::lookupByName(env, sourceName, source)) return False; |
| 33 | |
| 34 | if (!source->isRTPSource()) { |
| 35 | env.setResultMsg(sourceName, " is not a RTP source" ); |
| 36 | return False; |
| 37 | } |
| 38 | |
| 39 | resultSource = (RTPSource*)source; |
| 40 | return True; |
| 41 | } |
| 42 | |
| 43 | Boolean RTPSource::hasBeenSynchronizedUsingRTCP() { |
| 44 | return fCurPacketHasBeenSynchronizedUsingRTCP; |
| 45 | } |
| 46 | |
| 47 | Boolean RTPSource::isRTPSource() const { |
| 48 | return True; |
| 49 | } |
| 50 | |
| 51 | RTPSource::RTPSource(UsageEnvironment& env, Groupsock* RTPgs, |
| 52 | unsigned char rtpPayloadFormat, |
| 53 | u_int32_t rtpTimestampFrequency) |
| 54 | : FramedSource(env), |
| 55 | fRTPInterface(this, RTPgs), |
| 56 | fCurPacketHasBeenSynchronizedUsingRTCP(False), fLastReceivedSSRC(0), |
| 57 | fRTCPInstanceForMultiplexedRTCPPackets(NULL), |
| 58 | fRTPPayloadFormat(rtpPayloadFormat), fTimestampFrequency(rtpTimestampFrequency), |
| 59 | fSSRC(our_random32()), fEnableRTCPReports(True) { |
| 60 | fReceptionStatsDB = new RTPReceptionStatsDB(); |
| 61 | } |
| 62 | |
| 63 | RTPSource::~RTPSource() { |
| 64 | delete fReceptionStatsDB; |
| 65 | } |
| 66 | |
| 67 | void RTPSource::getAttributes() const { |
| 68 | envir().setResultMsg("" ); // Fix later to get attributes from header ##### |
| 69 | } |
| 70 | |
| 71 | |
| 72 | ////////// RTPReceptionStatsDB ////////// |
| 73 | |
| 74 | RTPReceptionStatsDB::RTPReceptionStatsDB() |
| 75 | : fTable(HashTable::create(ONE_WORD_HASH_KEYS)), fTotNumPacketsReceived(0) { |
| 76 | reset(); |
| 77 | } |
| 78 | |
| 79 | void RTPReceptionStatsDB::reset() { |
| 80 | fNumActiveSourcesSinceLastReset = 0; |
| 81 | |
| 82 | Iterator iter(*this); |
| 83 | RTPReceptionStats* stats; |
| 84 | while ((stats = iter.next()) != NULL) { |
| 85 | stats->reset(); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | RTPReceptionStatsDB::~RTPReceptionStatsDB() { |
| 90 | // First, remove and delete all stats records from the table: |
| 91 | RTPReceptionStats* stats; |
| 92 | while ((stats = (RTPReceptionStats*)fTable->RemoveNext()) != NULL) { |
| 93 | delete stats; |
| 94 | } |
| 95 | |
| 96 | // Then, delete the table itself: |
| 97 | delete fTable; |
| 98 | } |
| 99 | |
| 100 | void RTPReceptionStatsDB |
| 101 | ::noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum, |
| 102 | u_int32_t rtpTimestamp, unsigned timestampFrequency, |
| 103 | Boolean useForJitterCalculation, |
| 104 | struct timeval& resultPresentationTime, |
| 105 | Boolean& resultHasBeenSyncedUsingRTCP, |
| 106 | unsigned packetSize) { |
| 107 | ++fTotNumPacketsReceived; |
| 108 | RTPReceptionStats* stats = lookup(SSRC); |
| 109 | if (stats == NULL) { |
| 110 | // This is the first time we've heard from this SSRC. |
| 111 | // Create a new record for it: |
| 112 | stats = new RTPReceptionStats(SSRC, seqNum); |
| 113 | if (stats == NULL) return; |
| 114 | add(SSRC, stats); |
| 115 | } |
| 116 | |
| 117 | if (stats->numPacketsReceivedSinceLastReset() == 0) { |
| 118 | ++fNumActiveSourcesSinceLastReset; |
| 119 | } |
| 120 | |
| 121 | stats->noteIncomingPacket(seqNum, rtpTimestamp, timestampFrequency, |
| 122 | useForJitterCalculation, |
| 123 | resultPresentationTime, |
| 124 | resultHasBeenSyncedUsingRTCP, packetSize); |
| 125 | } |
| 126 | |
| 127 | void RTPReceptionStatsDB |
| 128 | ::noteIncomingSR(u_int32_t SSRC, |
| 129 | u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, |
| 130 | u_int32_t rtpTimestamp) { |
| 131 | RTPReceptionStats* stats = lookup(SSRC); |
| 132 | if (stats == NULL) { |
| 133 | // This is the first time we've heard of this SSRC. |
| 134 | // Create a new record for it: |
| 135 | stats = new RTPReceptionStats(SSRC); |
| 136 | if (stats == NULL) return; |
| 137 | add(SSRC, stats); |
| 138 | } |
| 139 | |
| 140 | stats->noteIncomingSR(ntpTimestampMSW, ntpTimestampLSW, rtpTimestamp); |
| 141 | } |
| 142 | |
| 143 | void RTPReceptionStatsDB::removeRecord(u_int32_t SSRC) { |
| 144 | RTPReceptionStats* stats = lookup(SSRC); |
| 145 | if (stats != NULL) { |
| 146 | long SSRC_long = (long)SSRC; |
| 147 | fTable->Remove((char const*)SSRC_long); |
| 148 | delete stats; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | RTPReceptionStatsDB::Iterator |
| 153 | ::Iterator(RTPReceptionStatsDB& receptionStatsDB) |
| 154 | : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) { |
| 155 | } |
| 156 | |
| 157 | RTPReceptionStatsDB::Iterator::~Iterator() { |
| 158 | delete fIter; |
| 159 | } |
| 160 | |
| 161 | RTPReceptionStats* |
| 162 | RTPReceptionStatsDB::Iterator::next(Boolean includeInactiveSources) { |
| 163 | char const* key; // dummy |
| 164 | |
| 165 | // If asked, skip over any sources that haven't been active |
| 166 | // since the last reset: |
| 167 | RTPReceptionStats* stats; |
| 168 | do { |
| 169 | stats = (RTPReceptionStats*)(fIter->next(key)); |
| 170 | } while (stats != NULL && !includeInactiveSources |
| 171 | && stats->numPacketsReceivedSinceLastReset() == 0); |
| 172 | |
| 173 | return stats; |
| 174 | } |
| 175 | |
| 176 | RTPReceptionStats* RTPReceptionStatsDB::lookup(u_int32_t SSRC) const { |
| 177 | long SSRC_long = (long)SSRC; |
| 178 | return (RTPReceptionStats*)(fTable->Lookup((char const*)SSRC_long)); |
| 179 | } |
| 180 | |
| 181 | void RTPReceptionStatsDB::add(u_int32_t SSRC, RTPReceptionStats* stats) { |
| 182 | long SSRC_long = (long)SSRC; |
| 183 | fTable->Add((char const*)SSRC_long, stats); |
| 184 | } |
| 185 | |
| 186 | ////////// RTPReceptionStats ////////// |
| 187 | |
| 188 | RTPReceptionStats::RTPReceptionStats(u_int32_t SSRC, u_int16_t initialSeqNum) { |
| 189 | initSeqNum(initialSeqNum); |
| 190 | init(SSRC); |
| 191 | } |
| 192 | |
| 193 | RTPReceptionStats::RTPReceptionStats(u_int32_t SSRC) { |
| 194 | init(SSRC); |
| 195 | } |
| 196 | |
| 197 | RTPReceptionStats::~RTPReceptionStats() { |
| 198 | } |
| 199 | |
| 200 | void RTPReceptionStats::init(u_int32_t SSRC) { |
| 201 | fSSRC = SSRC; |
| 202 | fTotNumPacketsReceived = 0; |
| 203 | fTotBytesReceived_hi = fTotBytesReceived_lo = 0; |
| 204 | fBaseExtSeqNumReceived = 0; |
| 205 | fHighestExtSeqNumReceived = 0; |
| 206 | fHaveSeenInitialSequenceNumber = False; |
| 207 | fLastTransit = ~0; |
| 208 | fPreviousPacketRTPTimestamp = 0; |
| 209 | fJitter = 0.0; |
| 210 | fLastReceivedSR_NTPmsw = fLastReceivedSR_NTPlsw = 0; |
| 211 | fLastReceivedSR_time.tv_sec = fLastReceivedSR_time.tv_usec = 0; |
| 212 | fLastPacketReceptionTime.tv_sec = fLastPacketReceptionTime.tv_usec = 0; |
| 213 | fMinInterPacketGapUS = 0x7FFFFFFF; |
| 214 | fMaxInterPacketGapUS = 0; |
| 215 | fTotalInterPacketGaps.tv_sec = fTotalInterPacketGaps.tv_usec = 0; |
| 216 | fHasBeenSynchronized = False; |
| 217 | fSyncTime.tv_sec = fSyncTime.tv_usec = 0; |
| 218 | reset(); |
| 219 | } |
| 220 | |
| 221 | void RTPReceptionStats::initSeqNum(u_int16_t initialSeqNum) { |
| 222 | fBaseExtSeqNumReceived = 0x10000 | initialSeqNum; |
| 223 | fHighestExtSeqNumReceived = 0x10000 | initialSeqNum; |
| 224 | fHaveSeenInitialSequenceNumber = True; |
| 225 | } |
| 226 | |
| 227 | #ifndef MILLION |
| 228 | #define MILLION 1000000 |
| 229 | #endif |
| 230 | |
| 231 | void RTPReceptionStats |
| 232 | ::noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp, |
| 233 | unsigned timestampFrequency, |
| 234 | Boolean useForJitterCalculation, |
| 235 | struct timeval& resultPresentationTime, |
| 236 | Boolean& resultHasBeenSyncedUsingRTCP, |
| 237 | unsigned packetSize) { |
| 238 | if (!fHaveSeenInitialSequenceNumber) initSeqNum(seqNum); |
| 239 | |
| 240 | ++fNumPacketsReceivedSinceLastReset; |
| 241 | ++fTotNumPacketsReceived; |
| 242 | u_int32_t prevTotBytesReceived_lo = fTotBytesReceived_lo; |
| 243 | fTotBytesReceived_lo += packetSize; |
| 244 | if (fTotBytesReceived_lo < prevTotBytesReceived_lo) { // wrap-around |
| 245 | ++fTotBytesReceived_hi; |
| 246 | } |
| 247 | |
| 248 | // Check whether the new sequence number is the highest yet seen: |
| 249 | unsigned oldSeqNum = (fHighestExtSeqNumReceived&0xFFFF); |
| 250 | unsigned seqNumCycle = (fHighestExtSeqNumReceived&0xFFFF0000); |
| 251 | unsigned seqNumDifference = (unsigned)((int)seqNum-(int)oldSeqNum); |
| 252 | unsigned newSeqNum = 0; |
| 253 | if (seqNumLT((u_int16_t)oldSeqNum, seqNum)) { |
| 254 | // This packet was not an old packet received out of order, so check it: |
| 255 | |
| 256 | if (seqNumDifference >= 0x8000) { |
| 257 | // The sequence number wrapped around, so start a new cycle: |
| 258 | seqNumCycle += 0x10000; |
| 259 | } |
| 260 | |
| 261 | newSeqNum = seqNumCycle|seqNum; |
| 262 | if (newSeqNum > fHighestExtSeqNumReceived) { |
| 263 | fHighestExtSeqNumReceived = newSeqNum; |
| 264 | } |
| 265 | } else if (fTotNumPacketsReceived > 1) { |
| 266 | // This packet was an old packet received out of order |
| 267 | |
| 268 | if ((int)seqNumDifference >= 0x8000) { |
| 269 | // The sequence number wrapped around, so switch to an old cycle: |
| 270 | seqNumCycle -= 0x10000; |
| 271 | } |
| 272 | |
| 273 | newSeqNum = seqNumCycle|seqNum; |
| 274 | if (newSeqNum < fBaseExtSeqNumReceived) { |
| 275 | fBaseExtSeqNumReceived = newSeqNum; |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | // Record the inter-packet delay |
| 280 | struct timeval timeNow; |
| 281 | gettimeofday(&timeNow, NULL); |
| 282 | if (fLastPacketReceptionTime.tv_sec != 0 |
| 283 | || fLastPacketReceptionTime.tv_usec != 0) { |
| 284 | unsigned gap |
| 285 | = (timeNow.tv_sec - fLastPacketReceptionTime.tv_sec)*MILLION |
| 286 | + timeNow.tv_usec - fLastPacketReceptionTime.tv_usec; |
| 287 | if (gap > fMaxInterPacketGapUS) { |
| 288 | fMaxInterPacketGapUS = gap; |
| 289 | } |
| 290 | if (gap < fMinInterPacketGapUS) { |
| 291 | fMinInterPacketGapUS = gap; |
| 292 | } |
| 293 | fTotalInterPacketGaps.tv_usec += gap; |
| 294 | if (fTotalInterPacketGaps.tv_usec >= MILLION) { |
| 295 | ++fTotalInterPacketGaps.tv_sec; |
| 296 | fTotalInterPacketGaps.tv_usec -= MILLION; |
| 297 | } |
| 298 | } |
| 299 | fLastPacketReceptionTime = timeNow; |
| 300 | |
| 301 | // Compute the current 'jitter' using the received packet's RTP timestamp, |
| 302 | // and the RTP timestamp that would correspond to the current time. |
| 303 | // (Use the code from appendix A.8 in the RTP spec.) |
| 304 | // Note, however, that we don't use this packet if its timestamp is |
| 305 | // the same as that of the previous packet (this indicates a multi-packet |
| 306 | // fragment), or if we've been explicitly told not to use this packet. |
| 307 | if (useForJitterCalculation |
| 308 | && rtpTimestamp != fPreviousPacketRTPTimestamp) { |
| 309 | unsigned arrival = (timestampFrequency*timeNow.tv_sec); |
| 310 | arrival += (unsigned) |
| 311 | ((2.0*timestampFrequency*timeNow.tv_usec + 1000000.0)/2000000); |
| 312 | // note: rounding |
| 313 | int transit = arrival - rtpTimestamp; |
| 314 | if (fLastTransit == (~0)) fLastTransit = transit; // hack for first time |
| 315 | int d = transit - fLastTransit; |
| 316 | fLastTransit = transit; |
| 317 | if (d < 0) d = -d; |
| 318 | fJitter += (1.0/16.0) * ((double)d - fJitter); |
| 319 | } |
| 320 | |
| 321 | // Return the 'presentation time' that corresponds to "rtpTimestamp": |
| 322 | if (fSyncTime.tv_sec == 0 && fSyncTime.tv_usec == 0) { |
| 323 | // This is the first timestamp that we've seen, so use the current |
| 324 | // 'wall clock' time as the synchronization time. (This will be |
| 325 | // corrected later when we receive RTCP SRs.) |
| 326 | fSyncTimestamp = rtpTimestamp; |
| 327 | fSyncTime = timeNow; |
| 328 | } |
| 329 | |
| 330 | int timestampDiff = rtpTimestamp - fSyncTimestamp; |
| 331 | // Note: This works even if the timestamp wraps around |
| 332 | // (as long as "int" is 32 bits) |
| 333 | |
| 334 | // Divide this by the timestamp frequency to get real time: |
| 335 | double timeDiff = timestampDiff/(double)timestampFrequency; |
| 336 | |
| 337 | // Add this to the 'sync time' to get our result: |
| 338 | unsigned const million = 1000000; |
| 339 | unsigned seconds, uSeconds; |
| 340 | if (timeDiff >= 0.0) { |
| 341 | seconds = fSyncTime.tv_sec + (unsigned)(timeDiff); |
| 342 | uSeconds = fSyncTime.tv_usec |
| 343 | + (unsigned)((timeDiff - (unsigned)timeDiff)*million); |
| 344 | if (uSeconds >= million) { |
| 345 | uSeconds -= million; |
| 346 | ++seconds; |
| 347 | } |
| 348 | } else { |
| 349 | timeDiff = -timeDiff; |
| 350 | seconds = fSyncTime.tv_sec - (unsigned)(timeDiff); |
| 351 | uSeconds = fSyncTime.tv_usec |
| 352 | - (unsigned)((timeDiff - (unsigned)timeDiff)*million); |
| 353 | if ((int)uSeconds < 0) { |
| 354 | uSeconds += million; |
| 355 | --seconds; |
| 356 | } |
| 357 | } |
| 358 | resultPresentationTime.tv_sec = seconds; |
| 359 | resultPresentationTime.tv_usec = uSeconds; |
| 360 | resultHasBeenSyncedUsingRTCP = fHasBeenSynchronized; |
| 361 | |
| 362 | // Save these as the new synchronization timestamp & time: |
| 363 | fSyncTimestamp = rtpTimestamp; |
| 364 | fSyncTime = resultPresentationTime; |
| 365 | |
| 366 | fPreviousPacketRTPTimestamp = rtpTimestamp; |
| 367 | } |
| 368 | |
| 369 | void RTPReceptionStats::noteIncomingSR(u_int32_t ntpTimestampMSW, |
| 370 | u_int32_t ntpTimestampLSW, |
| 371 | u_int32_t rtpTimestamp) { |
| 372 | fLastReceivedSR_NTPmsw = ntpTimestampMSW; |
| 373 | fLastReceivedSR_NTPlsw = ntpTimestampLSW; |
| 374 | |
| 375 | gettimeofday(&fLastReceivedSR_time, NULL); |
| 376 | |
| 377 | // Use this SR to update time synchronization information: |
| 378 | fSyncTimestamp = rtpTimestamp; |
| 379 | fSyncTime.tv_sec = ntpTimestampMSW - 0x83AA7E80; // 1/1/1900 -> 1/1/1970 |
| 380 | double microseconds = (ntpTimestampLSW*15625.0)/0x04000000; // 10^6/2^32 |
| 381 | fSyncTime.tv_usec = (unsigned)(microseconds+0.5); |
| 382 | fHasBeenSynchronized = True; |
| 383 | } |
| 384 | |
| 385 | double RTPReceptionStats::totNumKBytesReceived() const { |
| 386 | double const hiMultiplier = 0x20000000/125.0; // == (2^32)/(10^3) |
| 387 | return fTotBytesReceived_hi*hiMultiplier + fTotBytesReceived_lo/1000.0; |
| 388 | } |
| 389 | |
| 390 | unsigned RTPReceptionStats::jitter() const { |
| 391 | return (unsigned)fJitter; |
| 392 | } |
| 393 | |
| 394 | void RTPReceptionStats::reset() { |
| 395 | fNumPacketsReceivedSinceLastReset = 0; |
| 396 | fLastResetExtSeqNumReceived = fHighestExtSeqNumReceived; |
| 397 | } |
| 398 | |
| 399 | Boolean seqNumLT(u_int16_t s1, u_int16_t s2) { |
| 400 | // a 'less-than' on 16-bit sequence numbers |
| 401 | int diff = s2-s1; |
| 402 | if (diff > 0) { |
| 403 | return (diff < 0x8000); |
| 404 | } else if (diff < 0) { |
| 405 | return (diff < -0x8000); |
| 406 | } else { // diff == 0 |
| 407 | return False; |
| 408 | } |
| 409 | } |
| 410 | |