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 | |