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 Sinks |
19 | // Implementation |
20 | |
21 | #include "RTPSink.hh" |
22 | #include "GroupsockHelper.hh" |
23 | |
24 | ////////// RTPSink ////////// |
25 | |
26 | Boolean RTPSink::lookupByName(UsageEnvironment& env, char const* sinkName, |
27 | RTPSink*& resultSink) { |
28 | resultSink = NULL; // unless we succeed |
29 | |
30 | MediaSink* sink; |
31 | if (!MediaSink::lookupByName(env, sinkName, sink)) return False; |
32 | |
33 | if (!sink->isRTPSink()) { |
34 | env.setResultMsg(sinkName, " is not a RTP sink" ); |
35 | return False; |
36 | } |
37 | |
38 | resultSink = (RTPSink*)sink; |
39 | return True; |
40 | } |
41 | |
42 | Boolean RTPSink::isRTPSink() const { |
43 | return True; |
44 | } |
45 | |
46 | RTPSink::RTPSink(UsageEnvironment& env, |
47 | Groupsock* rtpGS, unsigned char rtpPayloadType, |
48 | unsigned rtpTimestampFrequency, |
49 | char const* rtpPayloadFormatName, |
50 | unsigned numChannels) |
51 | : MediaSink(env), fRTPInterface(this, rtpGS), |
52 | fRTPPayloadType(rtpPayloadType), |
53 | fPacketCount(0), fOctetCount(0), fTotalOctetCount(0), |
54 | fTimestampFrequency(rtpTimestampFrequency), fNextTimestampHasBeenPreset(False), fEnableRTCPReports(True), |
55 | fNumChannels(numChannels), fEstimatedBitrate(0) { |
56 | fRTPPayloadFormatName |
57 | = strDup(rtpPayloadFormatName == NULL ? "???" : rtpPayloadFormatName); |
58 | gettimeofday(&fCreationTime, NULL); |
59 | fTotalOctetCountStartTime = fCreationTime; |
60 | resetPresentationTimes(); |
61 | |
62 | fSeqNo = (u_int16_t)our_random(); |
63 | fSSRC = our_random32(); |
64 | fTimestampBase = our_random32(); |
65 | |
66 | fTransmissionStatsDB = new RTPTransmissionStatsDB(*this); |
67 | } |
68 | |
69 | RTPSink::~RTPSink() { |
70 | delete fTransmissionStatsDB; |
71 | delete[] (char*)fRTPPayloadFormatName; |
72 | fRTPInterface.forgetOurGroupsock(); |
73 | // so that the "fRTCPInterface" destructor doesn't turn off background read handling (in case |
74 | // its 'groupsock' is being shared with something else that does background read handling). |
75 | } |
76 | |
77 | u_int32_t RTPSink::convertToRTPTimestamp(struct timeval tv) { |
78 | // Begin by converting from "struct timeval" units to RTP timestamp units: |
79 | u_int32_t timestampIncrement = (fTimestampFrequency*tv.tv_sec); |
80 | timestampIncrement += (u_int32_t)(fTimestampFrequency*(tv.tv_usec/1000000.0) + 0.5); // note: rounding |
81 | |
82 | // Then add this to our 'timestamp base': |
83 | if (fNextTimestampHasBeenPreset) { |
84 | // Make the returned timestamp the same as the current "fTimestampBase", |
85 | // so that timestamps begin with the value that was previously preset: |
86 | fTimestampBase -= timestampIncrement; |
87 | fNextTimestampHasBeenPreset = False; |
88 | } |
89 | |
90 | u_int32_t const rtpTimestamp = fTimestampBase + timestampIncrement; |
91 | #ifdef DEBUG_TIMESTAMPS |
92 | fprintf(stderr, "fTimestampBase: 0x%08x, tv: %lu.%06ld\n\t=> RTP timestamp: 0x%08x\n" , |
93 | fTimestampBase, tv.tv_sec, tv.tv_usec, rtpTimestamp); |
94 | fflush(stderr); |
95 | #endif |
96 | |
97 | return rtpTimestamp; |
98 | } |
99 | |
100 | u_int32_t RTPSink::presetNextTimestamp() { |
101 | struct timeval timeNow; |
102 | gettimeofday(&timeNow, NULL); |
103 | |
104 | u_int32_t tsNow = convertToRTPTimestamp(timeNow); |
105 | if (!groupsockBeingUsed().hasMultipleDestinations()) { |
106 | // Don't adjust the timestamp stream if we already have another destination ongoing |
107 | fTimestampBase = tsNow; |
108 | fNextTimestampHasBeenPreset = True; |
109 | } |
110 | |
111 | return tsNow; |
112 | } |
113 | |
114 | void RTPSink::getTotalBitrate(unsigned& outNumBytes, double& outElapsedTime) { |
115 | struct timeval timeNow; |
116 | gettimeofday(&timeNow, NULL); |
117 | |
118 | outNumBytes = fTotalOctetCount; |
119 | outElapsedTime = (double)(timeNow.tv_sec-fTotalOctetCountStartTime.tv_sec) |
120 | + (timeNow.tv_usec-fTotalOctetCountStartTime.tv_usec)/1000000.0; |
121 | |
122 | fTotalOctetCount = 0; |
123 | fTotalOctetCountStartTime = timeNow; |
124 | } |
125 | |
126 | void RTPSink::resetPresentationTimes() { |
127 | fInitialPresentationTime.tv_sec = fMostRecentPresentationTime.tv_sec = 0; |
128 | fInitialPresentationTime.tv_usec = fMostRecentPresentationTime.tv_usec = 0; |
129 | } |
130 | |
131 | char const* RTPSink::sdpMediaType() const { |
132 | return "data" ; |
133 | // default SDP media (m=) type, unless redefined by subclasses |
134 | } |
135 | |
136 | char* RTPSink::rtpmapLine() const { |
137 | if (rtpPayloadType() >= 96) { // the payload format type is dynamic |
138 | char* encodingParamsPart; |
139 | if (numChannels() != 1) { |
140 | encodingParamsPart = new char[1 + 20 /* max int len */]; |
141 | sprintf(encodingParamsPart, "/%d" , numChannels()); |
142 | } else { |
143 | encodingParamsPart = strDup("" ); |
144 | } |
145 | char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n" ; |
146 | unsigned rtpmapFmtSize = strlen(rtpmapFmt) |
147 | + 3 /* max char len */ + strlen(rtpPayloadFormatName()) |
148 | + 20 /* max int len */ + strlen(encodingParamsPart); |
149 | char* rtpmapLine = new char[rtpmapFmtSize]; |
150 | sprintf(rtpmapLine, rtpmapFmt, |
151 | rtpPayloadType(), rtpPayloadFormatName(), |
152 | rtpTimestampFrequency(), encodingParamsPart); |
153 | delete[] encodingParamsPart; |
154 | |
155 | return rtpmapLine; |
156 | } else { |
157 | // The payload format is staic, so there's no "a=rtpmap:" line: |
158 | return strDup("" ); |
159 | } |
160 | } |
161 | |
162 | char const* RTPSink::auxSDPLine() { |
163 | return NULL; // by default |
164 | } |
165 | |
166 | |
167 | ////////// RTPTransmissionStatsDB ////////// |
168 | |
169 | RTPTransmissionStatsDB::RTPTransmissionStatsDB(RTPSink& rtpSink) |
170 | : fOurRTPSink(rtpSink), |
171 | fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { |
172 | fNumReceivers=0; |
173 | } |
174 | |
175 | RTPTransmissionStatsDB::~RTPTransmissionStatsDB() { |
176 | // First, remove and delete all stats records from the table: |
177 | RTPTransmissionStats* stats; |
178 | while ((stats = (RTPTransmissionStats*)fTable->RemoveNext()) != NULL) { |
179 | delete stats; |
180 | } |
181 | |
182 | // Then, delete the table itself: |
183 | delete fTable; |
184 | } |
185 | |
186 | void RTPTransmissionStatsDB |
187 | ::noteIncomingRR(u_int32_t SSRC, struct sockaddr_in const& lastFromAddress, |
188 | unsigned lossStats, unsigned lastPacketNumReceived, |
189 | unsigned jitter, unsigned lastSRTime, unsigned diffSR_RRTime) { |
190 | RTPTransmissionStats* stats = lookup(SSRC); |
191 | if (stats == NULL) { |
192 | // This is the first time we've heard of this SSRC. |
193 | // Create a new record for it: |
194 | stats = new RTPTransmissionStats(fOurRTPSink, SSRC); |
195 | if (stats == NULL) return; |
196 | add(SSRC, stats); |
197 | #ifdef DEBUG_RR |
198 | fprintf(stderr, "Adding new entry for SSRC %x in RTPTransmissionStatsDB\n" , SSRC); |
199 | #endif |
200 | } |
201 | |
202 | stats->noteIncomingRR(lastFromAddress, |
203 | lossStats, lastPacketNumReceived, jitter, |
204 | lastSRTime, diffSR_RRTime); |
205 | } |
206 | |
207 | void RTPTransmissionStatsDB::removeRecord(u_int32_t SSRC) { |
208 | RTPTransmissionStats* stats = lookup(SSRC); |
209 | if (stats != NULL) { |
210 | long SSRC_long = (long)SSRC; |
211 | fTable->Remove((char const*)SSRC_long); |
212 | --fNumReceivers; |
213 | delete stats; |
214 | } |
215 | } |
216 | |
217 | RTPTransmissionStatsDB::Iterator |
218 | ::Iterator(RTPTransmissionStatsDB& receptionStatsDB) |
219 | : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) { |
220 | } |
221 | |
222 | RTPTransmissionStatsDB::Iterator::~Iterator() { |
223 | delete fIter; |
224 | } |
225 | |
226 | RTPTransmissionStats* |
227 | RTPTransmissionStatsDB::Iterator::next() { |
228 | char const* key; // dummy |
229 | |
230 | return (RTPTransmissionStats*)(fIter->next(key)); |
231 | } |
232 | |
233 | RTPTransmissionStats* RTPTransmissionStatsDB::lookup(u_int32_t SSRC) const { |
234 | long SSRC_long = (long)SSRC; |
235 | return (RTPTransmissionStats*)(fTable->Lookup((char const*)SSRC_long)); |
236 | } |
237 | |
238 | void RTPTransmissionStatsDB::add(u_int32_t SSRC, RTPTransmissionStats* stats) { |
239 | long SSRC_long = (long)SSRC; |
240 | fTable->Add((char const*)SSRC_long, stats); |
241 | ++fNumReceivers; |
242 | } |
243 | |
244 | |
245 | ////////// RTPTransmissionStats ////////// |
246 | |
247 | RTPTransmissionStats::RTPTransmissionStats(RTPSink& rtpSink, u_int32_t SSRC) |
248 | : fOurRTPSink(rtpSink), fSSRC(SSRC), fLastPacketNumReceived(0), |
249 | fPacketLossRatio(0), fTotNumPacketsLost(0), fJitter(0), |
250 | fLastSRTime(0), fDiffSR_RRTime(0), fAtLeastTwoRRsHaveBeenReceived(False), fFirstPacket(True), |
251 | fTotalOctetCount_hi(0), fTotalOctetCount_lo(0), |
252 | fTotalPacketCount_hi(0), fTotalPacketCount_lo(0) { |
253 | gettimeofday(&fTimeCreated, NULL); |
254 | |
255 | fLastOctetCount = rtpSink.octetCount(); |
256 | fLastPacketCount = rtpSink.packetCount(); |
257 | } |
258 | |
259 | RTPTransmissionStats::~RTPTransmissionStats() {} |
260 | |
261 | void RTPTransmissionStats |
262 | ::noteIncomingRR(struct sockaddr_in const& lastFromAddress, |
263 | unsigned lossStats, unsigned lastPacketNumReceived, |
264 | unsigned jitter, unsigned lastSRTime, |
265 | unsigned diffSR_RRTime) { |
266 | if (fFirstPacket) { |
267 | fFirstPacket = False; |
268 | fFirstPacketNumReported = lastPacketNumReceived; |
269 | } else { |
270 | fAtLeastTwoRRsHaveBeenReceived = True; |
271 | fOldLastPacketNumReceived = fLastPacketNumReceived; |
272 | fOldTotNumPacketsLost = fTotNumPacketsLost; |
273 | } |
274 | gettimeofday(&fTimeReceived, NULL); |
275 | |
276 | fLastFromAddress = lastFromAddress; |
277 | fPacketLossRatio = lossStats>>24; |
278 | fTotNumPacketsLost = lossStats&0xFFFFFF; |
279 | fLastPacketNumReceived = lastPacketNumReceived; |
280 | fJitter = jitter; |
281 | fLastSRTime = lastSRTime; |
282 | fDiffSR_RRTime = diffSR_RRTime; |
283 | #ifdef DEBUG_RR |
284 | fprintf(stderr, "RTCP RR data (received at %lu.%06ld): lossStats 0x%08x, lastPacketNumReceived 0x%08x, jitter 0x%08x, lastSRTime 0x%08x, diffSR_RRTime 0x%08x\n" , |
285 | fTimeReceived.tv_sec, fTimeReceived.tv_usec, lossStats, lastPacketNumReceived, jitter, lastSRTime, diffSR_RRTime); |
286 | unsigned rtd = roundTripDelay(); |
287 | fprintf(stderr, "=> round-trip delay: 0x%04x (== %f seconds)\n" , rtd, rtd/65536.0); |
288 | #endif |
289 | |
290 | // Update our counts of the total number of octets and packets sent towards |
291 | // this receiver: |
292 | u_int32_t newOctetCount = fOurRTPSink.octetCount(); |
293 | u_int32_t octetCountDiff = newOctetCount - fLastOctetCount; |
294 | fLastOctetCount = newOctetCount; |
295 | u_int32_t prevTotalOctetCount_lo = fTotalOctetCount_lo; |
296 | fTotalOctetCount_lo += octetCountDiff; |
297 | if (fTotalOctetCount_lo < prevTotalOctetCount_lo) { // wrap around |
298 | ++fTotalOctetCount_hi; |
299 | } |
300 | |
301 | u_int32_t newPacketCount = fOurRTPSink.packetCount(); |
302 | u_int32_t packetCountDiff = newPacketCount - fLastPacketCount; |
303 | fLastPacketCount = newPacketCount; |
304 | u_int32_t prevTotalPacketCount_lo = fTotalPacketCount_lo; |
305 | fTotalPacketCount_lo += packetCountDiff; |
306 | if (fTotalPacketCount_lo < prevTotalPacketCount_lo) { // wrap around |
307 | ++fTotalPacketCount_hi; |
308 | } |
309 | } |
310 | |
311 | unsigned RTPTransmissionStats::roundTripDelay() const { |
312 | // Compute the round-trip delay that was indicated by the most recently-received |
313 | // RTCP RR packet. Use the method noted in the RTP/RTCP specification (RFC 3350). |
314 | |
315 | if (fLastSRTime == 0) { |
316 | // Either no RTCP RR packet has been received yet, or else the |
317 | // reporting receiver has not yet received any RTCP SR packets from us: |
318 | return 0; |
319 | } |
320 | |
321 | // First, convert the time that we received the last RTCP RR packet to NTP format, |
322 | // in units of 1/65536 (2^-16) seconds: |
323 | unsigned lastReceivedTimeNTP_high |
324 | = fTimeReceived.tv_sec + 0x83AA7E80; // 1970 epoch -> 1900 epoch |
325 | double fractionalPart = (fTimeReceived.tv_usec*0x0400)/15625.0; // 2^16/10^6 |
326 | unsigned lastReceivedTimeNTP |
327 | = (unsigned)((lastReceivedTimeNTP_high<<16) + fractionalPart + 0.5); |
328 | |
329 | int rawResult = lastReceivedTimeNTP - fLastSRTime - fDiffSR_RRTime; |
330 | if (rawResult < 0) { |
331 | // This can happen if there's clock drift between the sender and receiver, |
332 | // and if the round-trip time was very small. |
333 | rawResult = 0; |
334 | } |
335 | return (unsigned)rawResult; |
336 | } |
337 | |
338 | void RTPTransmissionStats::getTotalOctetCount(u_int32_t& hi, u_int32_t& lo) { |
339 | hi = fTotalOctetCount_hi; |
340 | lo = fTotalOctetCount_lo; |
341 | } |
342 | |
343 | void RTPTransmissionStats::getTotalPacketCount(u_int32_t& hi, u_int32_t& lo) { |
344 | hi = fTotalPacketCount_hi; |
345 | lo = fTotalPacketCount_lo; |
346 | } |
347 | |
348 | unsigned RTPTransmissionStats::packetsReceivedSinceLastRR() const { |
349 | if (!fAtLeastTwoRRsHaveBeenReceived) return 0; |
350 | |
351 | return fLastPacketNumReceived-fOldLastPacketNumReceived; |
352 | } |
353 | |
354 | int RTPTransmissionStats::packetsLostBetweenRR() const { |
355 | if (!fAtLeastTwoRRsHaveBeenReceived) return 0; |
356 | |
357 | return fTotNumPacketsLost - fOldTotNumPacketsLost; |
358 | } |
359 | |