blob: ddeedccd9423e6f1b61059f7a6b78ebdf26e5bf8 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000011#include "webrtc/modules/rtp_rtcp/source/rtcp_receiver.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h> //assert
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000014#include <string.h> //memset
niklase@google.com470e71d2011-07-07 08:21:25 +000015
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000016#include <algorithm>
17
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000018#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
19#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
20#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
21#include "webrtc/system_wrappers/interface/trace.h"
22#include "webrtc/system_wrappers/interface/trace_event.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023
niklase@google.com470e71d2011-07-07 08:21:25 +000024namespace webrtc {
25using namespace RTCPUtility;
26using namespace RTCPHelp;
27
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +000028// The number of RTCP time intervals needed to trigger a timeout.
29const int kRrTimeoutIntervals = 3;
30
pbos@webrtc.org2f446732013-04-08 11:08:41 +000031RTCPReceiver::RTCPReceiver(const int32_t id, Clock* clock,
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +000032 ModuleRtpRtcpImpl* owner)
33 : TMMBRHelp(),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000034 _id(id),
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000035 _clock(clock),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000036 _method(kRtcpOff),
37 _lastReceived(0),
38 _rtpRtcp(*owner),
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +000039 _criticalSectionFeedbacks(
40 CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000041 _cbRtcpFeedback(NULL),
42 _cbRtcpBandwidthObserver(NULL),
43 _cbRtcpIntraFrameObserver(NULL),
44 _criticalSectionRTCPReceiver(
45 CriticalSectionWrapper::CreateCriticalSection()),
stefan@webrtc.org28a331e2013-09-17 07:49:56 +000046 main_ssrc_(0),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000047 _remoteSSRC(0),
48 _remoteSenderInfo(),
49 _lastReceivedSRNTPsecs(0),
50 _lastReceivedSRNTPfrac(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000051 _lastReceivedXRNTPsecs(0),
52 _lastReceivedXRNTPfrac(0),
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +000053 xr_rr_rtt_ms_(0),
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +000054 _receivedInfoMap(),
55 _packetTimeOutMS(0),
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +000056 _lastReceivedRrMs(0),
stefan@webrtc.org8ca8a712013-04-23 16:48:32 +000057 _lastIncreasedSequenceNumberMs(0),
58 _rtt(0) {
niklase@google.com470e71d2011-07-07 08:21:25 +000059 memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
60 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
61}
62
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000063RTCPReceiver::~RTCPReceiver() {
64 delete _criticalSectionRTCPReceiver;
65 delete _criticalSectionFeedbacks;
niklase@google.com470e71d2011-07-07 08:21:25 +000066
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000067 while (!_receivedReportBlockMap.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +000068 std::map<uint32_t, RTCPReportBlockInformation*>::iterator first =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000069 _receivedReportBlockMap.begin();
70 delete first->second;
71 _receivedReportBlockMap.erase(first);
72 }
73 while (!_receivedInfoMap.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +000074 std::map<uint32_t, RTCPReceiveInformation*>::iterator first =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000075 _receivedInfoMap.begin();
76 delete first->second;
77 _receivedInfoMap.erase(first);
78 }
79 while (!_receivedCnameMap.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +000080 std::map<uint32_t, RTCPCnameInformation*>::iterator first =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000081 _receivedCnameMap.begin();
82 delete first->second;
83 _receivedCnameMap.erase(first);
84 }
85 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id,
86 "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +000087}
88
89void
pbos@webrtc.org2f446732013-04-08 11:08:41 +000090RTCPReceiver::ChangeUniqueId(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +000091{
92 _id = id;
93}
94
95RTCPMethod
96RTCPReceiver::Status() const
97{
98 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
99 return _method;
100}
101
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000102int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000103RTCPReceiver::SetRTCPStatus(const RTCPMethod method)
104{
105 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
106 _method = method;
107 return 0;
108}
109
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000110int64_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000111RTCPReceiver::LastReceived()
112{
113 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
114 return _lastReceived;
115}
116
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000117int64_t
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000118RTCPReceiver::LastReceivedReceiverReport() const {
119 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000120 int64_t last_received_rr = -1;
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000121 for (ReceivedInfoMap::const_iterator it = _receivedInfoMap.begin();
122 it != _receivedInfoMap.end(); ++it) {
123 if (it->second->lastTimeReceived > last_received_rr) {
124 last_received_rr = it->second->lastTimeReceived;
125 }
126 }
127 return last_received_rr;
128}
129
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000130int32_t
131RTCPReceiver::SetRemoteSSRC( const uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000132{
133 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
134
135 // new SSRC reset old reports
136 memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
137 _lastReceivedSRNTPsecs = 0;
138 _lastReceivedSRNTPfrac = 0;
139
140 _remoteSSRC = ssrc;
141 return 0;
142}
143
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000144uint32_t RTCPReceiver::RemoteSSRC() const {
145 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
146 return _remoteSSRC;
147}
148
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +0000149void RTCPReceiver::RegisterRtcpObservers(
150 RtcpIntraFrameObserver* intra_frame_callback,
151 RtcpBandwidthObserver* bandwidth_callback,
152 RtcpFeedback* feedback_callback) {
153 CriticalSectionScoped lock(_criticalSectionFeedbacks);
154 _cbRtcpIntraFrameObserver = intra_frame_callback;
155 _cbRtcpBandwidthObserver = bandwidth_callback;
156 _cbRtcpFeedback = feedback_callback;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157}
158
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000159void RTCPReceiver::SetSsrcs(uint32_t main_ssrc,
160 const std::set<uint32_t>& registered_ssrcs) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000161 uint32_t old_ssrc = 0;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000162 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000163 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000164 old_ssrc = main_ssrc_;
165 main_ssrc_ = main_ssrc;
166 registered_ssrcs_ = registered_ssrcs;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000167 }
168 {
169 CriticalSectionScoped lock(_criticalSectionFeedbacks);
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000170 if (_cbRtcpIntraFrameObserver && old_ssrc != main_ssrc) {
171 _cbRtcpIntraFrameObserver->OnLocalSsrcChanged(old_ssrc, main_ssrc);
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000172 }
173 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000174}
175
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000176int32_t RTCPReceiver::ResetRTT(const uint32_t remoteSSRC) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000177 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
178 RTCPReportBlockInformation* reportBlock =
179 GetReportBlockInformation(remoteSSRC);
180 if (reportBlock == NULL) {
181 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
182 "\tfailed to GetReportBlockInformation(%u)", remoteSSRC);
183 return -1;
184 }
185 reportBlock->RTT = 0;
186 reportBlock->avgRTT = 0;
187 reportBlock->minRTT = 0;
188 reportBlock->maxRTT = 0;
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000189 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000190}
191
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000192int32_t RTCPReceiver::RTT(uint32_t remoteSSRC,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000193 uint16_t* RTT,
194 uint16_t* avgRTT,
195 uint16_t* minRTT,
196 uint16_t* maxRTT) const {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000197 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000199 RTCPReportBlockInformation* reportBlock =
200 GetReportBlockInformation(remoteSSRC);
201
202 if (reportBlock == NULL) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000203 return -1;
204 }
205 if (RTT) {
206 *RTT = reportBlock->RTT;
207 }
208 if (avgRTT) {
209 *avgRTT = reportBlock->avgRTT;
210 }
211 if (minRTT) {
212 *minRTT = reportBlock->minRTT;
213 }
214 if (maxRTT) {
215 *maxRTT = reportBlock->maxRTT;
216 }
217 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000218}
219
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000220bool RTCPReceiver::GetAndResetXrRrRtt(uint16_t* rtt_ms) {
221 assert(rtt_ms);
222 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
223 if (xr_rr_rtt_ms_ == 0) {
224 return false;
225 }
226 *rtt_ms = xr_rr_rtt_ms_;
227 xr_rr_rtt_ms_ = 0;
228 return true;
229}
230
stefan@webrtc.org8ca8a712013-04-23 16:48:32 +0000231uint16_t RTCPReceiver::RTT() const {
232 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
233 if (!_receivedReportBlockMap.empty()) {
234 return 0;
235 }
236 return _rtt;
237}
238
239int RTCPReceiver::SetRTT(uint16_t rtt) {
240 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
241 if (!_receivedReportBlockMap.empty()) {
242 return -1;
243 }
244 _rtt = rtt;
245 return 0;
246}
247
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000248int32_t
249RTCPReceiver::NTP(uint32_t *ReceivedNTPsecs,
250 uint32_t *ReceivedNTPfrac,
251 uint32_t *RTCPArrivalTimeSecs,
252 uint32_t *RTCPArrivalTimeFrac,
253 uint32_t *rtcp_timestamp) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000254{
255 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
256 if(ReceivedNTPsecs)
257 {
258 *ReceivedNTPsecs = _remoteSenderInfo.NTPseconds; // NTP from incoming SendReport
259 }
260 if(ReceivedNTPfrac)
261 {
262 *ReceivedNTPfrac = _remoteSenderInfo.NTPfraction;
263 }
264 if(RTCPArrivalTimeFrac)
265 {
266 *RTCPArrivalTimeFrac = _lastReceivedSRNTPfrac; // local NTP time when we received a RTCP packet with a send block
267 }
268 if(RTCPArrivalTimeSecs)
269 {
270 *RTCPArrivalTimeSecs = _lastReceivedSRNTPsecs;
271 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000272 if (rtcp_timestamp) {
273 *rtcp_timestamp = _remoteSenderInfo.RTPtimeStamp;
274 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 return 0;
276}
277
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000278bool RTCPReceiver::LastReceivedXrReferenceTimeInfo(
279 RtcpReceiveTimeInfo* info) const {
280 assert(info);
281 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
282 if (_lastReceivedXRNTPsecs == 0 && _lastReceivedXRNTPfrac == 0) {
283 return false;
284 }
285
286 info->sourceSSRC = _remoteXRReceiveTimeInfo.sourceSSRC;
287 info->lastRR = _remoteXRReceiveTimeInfo.lastRR;
288
289 // Get the delay since last received report (RFC 3611).
290 uint32_t receive_time = RTCPUtility::MidNtp(_lastReceivedXRNTPsecs,
291 _lastReceivedXRNTPfrac);
292
293 uint32_t ntp_sec = 0;
294 uint32_t ntp_frac = 0;
295 _clock->CurrentNtp(ntp_sec, ntp_frac);
296 uint32_t now = RTCPUtility::MidNtp(ntp_sec, ntp_frac);
297
298 info->delaySinceLastRR = now - receive_time;
299 return true;
300}
301
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000302int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000303RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
304{
305 if(senderInfo == NULL)
306 {
307 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
308 return -1;
309 }
310 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
311 if(_lastReceivedSRNTPsecs == 0)
312 {
313 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s No received SR", __FUNCTION__);
314 return -1;
315 }
316 memcpy(senderInfo, &(_remoteSenderInfo), sizeof(RTCPSenderInfo));
317 return 0;
318}
319
320// statistics
321// we can get multiple receive reports when we receive the report from a CE
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000322int32_t RTCPReceiver::StatisticsReceived(
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000323 std::vector<RTCPReportBlock>* receiveBlocks) const {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000324 assert(receiveBlocks);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000325 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
326
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000327 std::map<uint32_t, RTCPReportBlockInformation*>::const_iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000328 _receivedReportBlockMap.begin();
329
330 while (it != _receivedReportBlockMap.end()) {
331 receiveBlocks->push_back(it->second->remoteReceiveBlock);
332 it++;
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000333 }
334 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000335}
336
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000337int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000338RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
339 RTCPUtility::RTCPParserV2* rtcpParser)
340{
341 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
342
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000343 _lastReceived = _clock->TimeInMilliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
345 RTCPUtility::RTCPPacketTypes pktType = rtcpParser->Begin();
346 while (pktType != RTCPUtility::kRtcpNotValidCode)
347 {
348 // Each "case" is responsible for iterate the parser to the
349 // next top level packet.
350 switch (pktType)
351 {
352 case RTCPUtility::kRtcpSrCode:
353 case RTCPUtility::kRtcpRrCode:
354 HandleSenderReceiverReport(*rtcpParser, rtcpPacketInformation);
355 break;
356 case RTCPUtility::kRtcpSdesCode:
357 HandleSDES(*rtcpParser);
358 break;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000359 case RTCPUtility::kRtcpXrHeaderCode:
360 HandleXrHeader(*rtcpParser, rtcpPacketInformation);
361 break;
362 case RTCPUtility::kRtcpXrReceiverReferenceTimeCode:
363 HandleXrReceiveReferenceTime(*rtcpParser, rtcpPacketInformation);
364 break;
365 case RTCPUtility::kRtcpXrDlrrReportBlockCode:
366 HandleXrDlrrReportBlock(*rtcpParser, rtcpPacketInformation);
367 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 case RTCPUtility::kRtcpXrVoipMetricCode:
369 HandleXRVOIPMetric(*rtcpParser, rtcpPacketInformation);
370 break;
371 case RTCPUtility::kRtcpByeCode:
372 HandleBYE(*rtcpParser);
373 break;
374 case RTCPUtility::kRtcpRtpfbNackCode:
375 HandleNACK(*rtcpParser, rtcpPacketInformation);
376 break;
377 case RTCPUtility::kRtcpRtpfbTmmbrCode:
378 HandleTMMBR(*rtcpParser, rtcpPacketInformation);
379 break;
380 case RTCPUtility::kRtcpRtpfbTmmbnCode:
hta@webrtc.org9d54cd12012-04-30 08:24:55 +0000381 HandleTMMBN(*rtcpParser, rtcpPacketInformation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 break;
383 case RTCPUtility::kRtcpRtpfbSrReqCode:
384 HandleSR_REQ(*rtcpParser, rtcpPacketInformation);
385 break;
386 case RTCPUtility::kRtcpPsfbPliCode:
387 HandlePLI(*rtcpParser, rtcpPacketInformation);
388 break;
389 case RTCPUtility::kRtcpPsfbSliCode:
390 HandleSLI(*rtcpParser, rtcpPacketInformation);
391 break;
392 case RTCPUtility::kRtcpPsfbRpsiCode:
393 HandleRPSI(*rtcpParser, rtcpPacketInformation);
394 break;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000395 case RTCPUtility::kRtcpExtendedIjCode:
396 HandleIJ(*rtcpParser, rtcpPacketInformation);
397 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 case RTCPUtility::kRtcpPsfbFirCode:
399 HandleFIR(*rtcpParser, rtcpPacketInformation);
400 break;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000401 case RTCPUtility::kRtcpPsfbAppCode:
402 HandlePsfbApp(*rtcpParser, rtcpPacketInformation);
403 break;
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 case RTCPUtility::kRtcpAppCode:
405 // generic application messages
406 HandleAPP(*rtcpParser, rtcpPacketInformation);
407 break;
408 case RTCPUtility::kRtcpAppItemCode:
409 // generic application messages
410 HandleAPPItem(*rtcpParser, rtcpPacketInformation);
411 break;
412 default:
413 rtcpParser->Iterate();
414 break;
415 }
416 pktType = rtcpParser->PacketType();
417 }
418 return 0;
419}
420
421// no need for critsect we have _criticalSectionRTCPReceiver
422void
423RTCPReceiver::HandleSenderReceiverReport(RTCPUtility::RTCPParserV2& rtcpParser,
424 RTCPPacketInformation& rtcpPacketInformation)
425{
426 RTCPUtility::RTCPPacketTypes rtcpPacketType = rtcpParser.PacketType();
427 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
428
429 assert((rtcpPacketType == RTCPUtility::kRtcpRrCode) || (rtcpPacketType == RTCPUtility::kRtcpSrCode));
430
431 // SR.SenderSSRC
432 // The synchronization source identifier for the originator of this SR packet
433
434 // rtcpPacket.RR.SenderSSRC
435 // The source of the packet sender, same as of SR? or is this a CE?
436
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000437 const uint32_t remoteSSRC = (rtcpPacketType == RTCPUtility::kRtcpRrCode) ? rtcpPacket.RR.SenderSSRC:rtcpPacket.SR.SenderSSRC;
438 const uint8_t numberOfReportBlocks = (rtcpPacketType == RTCPUtility::kRtcpRrCode) ? rtcpPacket.RR.NumberOfReportBlocks:rtcpPacket.SR.NumberOfReportBlocks;
niklase@google.com470e71d2011-07-07 08:21:25 +0000439
440 rtcpPacketInformation.remoteSSRC = remoteSSRC;
441
442 RTCPReceiveInformation* ptrReceiveInfo = CreateReceiveInformation(remoteSSRC);
443 if (!ptrReceiveInfo)
444 {
445 rtcpParser.Iterate();
446 return;
447 }
448
449 if (rtcpPacketType == RTCPUtility::kRtcpSrCode)
450 {
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000451 TRACE_EVENT_INSTANT2("webrtc_rtp", "SR",
452 "remote_ssrc", remoteSSRC,
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000453 "ssrc", main_ssrc_);
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000454
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 if (_remoteSSRC == remoteSSRC) // have I received RTP packets from this party
456 {
457 // only signal that we have received a SR when we accept one
458 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSr;
459
stefan@webrtc.org976a7e62012-09-21 13:20:21 +0000460 rtcpPacketInformation.ntp_secs = rtcpPacket.SR.NTPMostSignificant;
461 rtcpPacketInformation.ntp_frac = rtcpPacket.SR.NTPLeastSignificant;
462 rtcpPacketInformation.rtp_timestamp = rtcpPacket.SR.RTPTimestamp;
463
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 // We will only store the send report from one source, but
465 // we will store all the receive block
466
467 // Save the NTP time of this report
468 _remoteSenderInfo.NTPseconds = rtcpPacket.SR.NTPMostSignificant;
469 _remoteSenderInfo.NTPfraction = rtcpPacket.SR.NTPLeastSignificant;
470 _remoteSenderInfo.RTPtimeStamp = rtcpPacket.SR.RTPTimestamp;
471 _remoteSenderInfo.sendPacketCount = rtcpPacket.SR.SenderPacketCount;
472 _remoteSenderInfo.sendOctetCount = rtcpPacket.SR.SenderOctetCount;
473
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000474 _clock->CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 }
476 else
477 {
478 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
479 }
480 } else
481 {
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000482 TRACE_EVENT_INSTANT2("webrtc_rtp", "RR",
483 "remote_ssrc", remoteSSRC,
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000484 "ssrc", main_ssrc_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
486 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
487 }
488 UpdateReceiveInformation(*ptrReceiveInfo);
489
490 rtcpPacketType = rtcpParser.Iterate();
491
492 while (rtcpPacketType == RTCPUtility::kRtcpReportBlockItemCode)
493 {
494 HandleReportBlock(rtcpPacket, rtcpPacketInformation, remoteSSRC, numberOfReportBlocks);
495 rtcpPacketType = rtcpParser.Iterate();
496 }
497}
498
499// no need for critsect we have _criticalSectionRTCPReceiver
500void
501RTCPReceiver::HandleReportBlock(const RTCPUtility::RTCPPacket& rtcpPacket,
502 RTCPPacketInformation& rtcpPacketInformation,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000503 const uint32_t remoteSSRC,
504 const uint8_t numberOfReportBlocks) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000505 // This will be called once per report block in the RTCP packet.
506 // We filter out all report blocks that are not for us.
507 // Each packet has max 31 RR blocks.
508 //
509 // We can calc RTT if we send a send report and get a report block back.
niklase@google.com470e71d2011-07-07 08:21:25 +0000510
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000511 // |rtcpPacket.ReportBlockItem.SSRC| is the SSRC identifier of the source to
512 // which the information in this reception report block pertains.
niklase@google.com470e71d2011-07-07 08:21:25 +0000513
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000514 // Filter out all report blocks that are not for us.
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000515 if (registered_ssrcs_.find(rtcpPacket.ReportBlockItem.SSRC) ==
516 registered_ssrcs_.end()) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000517 // This block is not for us ignore it.
518 return;
519 }
520
521 // To avoid problem with acquiring _criticalSectionRTCPSender while holding
522 // _criticalSectionRTCPReceiver.
523 _criticalSectionRTCPReceiver->Leave();
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000524 uint32_t sendTimeMS =
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000525 _rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
526 _criticalSectionRTCPReceiver->Enter();
527
528 RTCPReportBlockInformation* reportBlock =
529 CreateReportBlockInformation(remoteSSRC);
530 if (reportBlock == NULL) {
531 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
532 "\tfailed to CreateReportBlockInformation(%u)", remoteSSRC);
533 return;
534 }
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000535
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000536 _lastReceivedRrMs = _clock->TimeInMilliseconds();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000537 const RTCPPacketReportBlockItem& rb = rtcpPacket.ReportBlockItem;
538 reportBlock->remoteReceiveBlock.remoteSSRC = remoteSSRC;
539 reportBlock->remoteReceiveBlock.sourceSSRC = rb.SSRC;
540 reportBlock->remoteReceiveBlock.fractionLost = rb.FractionLost;
541 reportBlock->remoteReceiveBlock.cumulativeLost =
542 rb.CumulativeNumOfPacketsLost;
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000543 if (rb.ExtendedHighestSequenceNumber >
544 reportBlock->remoteReceiveBlock.extendedHighSeqNum) {
545 // We have successfully delivered new RTP packets to the remote side after
546 // the last RR was sent from the remote side.
547 _lastIncreasedSequenceNumberMs = _lastReceivedRrMs;
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000548 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000549 reportBlock->remoteReceiveBlock.extendedHighSeqNum =
550 rb.ExtendedHighestSequenceNumber;
551 reportBlock->remoteReceiveBlock.jitter = rb.Jitter;
552 reportBlock->remoteReceiveBlock.delaySinceLastSR = rb.DelayLastSR;
553 reportBlock->remoteReceiveBlock.lastSR = rb.LastSR;
554
555 if (rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter) {
556 reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter;
557 }
558
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000559 uint32_t delaySinceLastSendReport =
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000560 rtcpPacket.ReportBlockItem.DelayLastSR;
561
562 // local NTP time when we received this
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000563 uint32_t lastReceivedRRNTPsecs = 0;
564 uint32_t lastReceivedRRNTPfrac = 0;
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000565
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000566 _clock->CurrentNtp(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000567
568 // time when we received this in MS
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000569 uint32_t receiveTimeMS = Clock::NtpToMs(lastReceivedRRNTPsecs,
570 lastReceivedRRNTPfrac);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000571
572 // Estimate RTT
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000573 uint32_t d = (delaySinceLastSendReport & 0x0000ffff) * 1000;
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000574 d /= 65536;
575 d += ((delaySinceLastSendReport & 0xffff0000) >> 16) * 1000;
576
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000577 int32_t RTT = 0;
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000578
579 if (sendTimeMS > 0) {
580 RTT = receiveTimeMS - d - sendTimeMS;
581 if (RTT <= 0) {
582 RTT = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000584 if (RTT > reportBlock->maxRTT) {
585 // store max RTT
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000586 reportBlock->maxRTT = (uint16_t) RTT;
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000588 if (reportBlock->minRTT == 0) {
589 // first RTT
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000590 reportBlock->minRTT = (uint16_t) RTT;
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000591 } else if (RTT < reportBlock->minRTT) {
592 // Store min RTT
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000593 reportBlock->minRTT = (uint16_t) RTT;
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000595 // store last RTT
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000596 reportBlock->RTT = (uint16_t) RTT;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000598 // store average RTT
599 if (reportBlock->numAverageCalcs != 0) {
600 float ac = static_cast<float> (reportBlock->numAverageCalcs);
601 float newAverage = ((ac / (ac + 1)) * reportBlock->avgRTT)
602 + ((1 / (ac + 1)) * RTT);
603 reportBlock->avgRTT = static_cast<int> (newAverage + 0.5f);
604 } else {
605 // first RTT
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000606 reportBlock->avgRTT = (uint16_t) RTT;
niklase@google.com470e71d2011-07-07 08:21:25 +0000607 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000608 reportBlock->numAverageCalcs++;
609 }
610
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000611 TRACE_COUNTER_ID1("webrtc_rtp", "RR_RTT", rb.SSRC, RTT);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000612
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000613 rtcpPacketInformation.AddReportInfo(*reportBlock);
niklase@google.com470e71d2011-07-07 08:21:25 +0000614}
615
616RTCPReportBlockInformation*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000617RTCPReceiver::CreateReportBlockInformation(uint32_t remoteSSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000618 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000619
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000620 std::map<uint32_t, RTCPReportBlockInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000621 _receivedReportBlockMap.find(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000622
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000623 RTCPReportBlockInformation* ptrReportBlockInfo = NULL;
624 if (it != _receivedReportBlockMap.end()) {
625 ptrReportBlockInfo = it->second;
626 } else {
627 ptrReportBlockInfo = new RTCPReportBlockInformation;
628 _receivedReportBlockMap[remoteSSRC] = ptrReportBlockInfo;
629 }
630 return ptrReportBlockInfo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000631}
632
633RTCPReportBlockInformation*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000634RTCPReceiver::GetReportBlockInformation(uint32_t remoteSSRC) const {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000635 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000636
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000637 std::map<uint32_t, RTCPReportBlockInformation*>::const_iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000638 _receivedReportBlockMap.find(remoteSSRC);
639
640 if (it == _receivedReportBlockMap.end()) {
641 return NULL;
642 }
643 return it->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000644}
645
646RTCPCnameInformation*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000647RTCPReceiver::CreateCnameInformation(uint32_t remoteSSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000648 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000649
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000650 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000651 _receivedCnameMap.find(remoteSSRC);
652
653 if (it != _receivedCnameMap.end()) {
654 return it->second;
655 }
656 RTCPCnameInformation* cnameInfo = new RTCPCnameInformation;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000657 memset(cnameInfo->name, 0, RTCP_CNAME_SIZE);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000658 _receivedCnameMap[remoteSSRC] = cnameInfo;
659 return cnameInfo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000660}
661
662RTCPCnameInformation*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000663RTCPReceiver::GetCnameInformation(uint32_t remoteSSRC) const {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000664 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000665
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000666 std::map<uint32_t, RTCPCnameInformation*>::const_iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000667 _receivedCnameMap.find(remoteSSRC);
668
669 if (it == _receivedCnameMap.end()) {
670 return NULL;
671 }
672 return it->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000673}
674
675RTCPReceiveInformation*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000676RTCPReceiver::CreateReceiveInformation(uint32_t remoteSSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000677 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000678
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000679 std::map<uint32_t, RTCPReceiveInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000680 _receivedInfoMap.find(remoteSSRC);
681
682 if (it != _receivedInfoMap.end()) {
683 return it->second;
684 }
685 RTCPReceiveInformation* receiveInfo = new RTCPReceiveInformation;
686 _receivedInfoMap[remoteSSRC] = receiveInfo;
687 return receiveInfo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000688}
689
690RTCPReceiveInformation*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000691RTCPReceiver::GetReceiveInformation(uint32_t remoteSSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000692 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000693
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000694 std::map<uint32_t, RTCPReceiveInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000695 _receivedInfoMap.find(remoteSSRC);
696 if (it == _receivedInfoMap.end()) {
697 return NULL;
698 }
699 return it->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000700}
701
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000702void RTCPReceiver::UpdateReceiveInformation(
703 RTCPReceiveInformation& receiveInformation) {
704 // Update that this remote is alive
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000705 receiveInformation.lastTimeReceived = _clock->TimeInMilliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000706}
707
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000708bool RTCPReceiver::RtcpRrTimeout(int64_t rtcp_interval_ms) {
709 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
710 if (_lastReceivedRrMs == 0)
711 return false;
712
713 int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000714 if (_clock->TimeInMilliseconds() > _lastReceivedRrMs + time_out_ms) {
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000715 // Reset the timer to only trigger one log.
716 _lastReceivedRrMs = 0;
717 return true;
718 }
719 return false;
720}
721
722bool RTCPReceiver::RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms) {
723 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
724 if (_lastIncreasedSequenceNumberMs == 0)
725 return false;
726
727 int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000728 if (_clock->TimeInMilliseconds() > _lastIncreasedSequenceNumberMs +
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000729 time_out_ms) {
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000730 // Reset the timer to only trigger one log.
731 _lastIncreasedSequenceNumberMs = 0;
732 return true;
733 }
734 return false;
735}
736
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000737bool RTCPReceiver::UpdateRTCPReceiveInformationTimers() {
738 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000739
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000740 bool updateBoundingSet = false;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000741 int64_t timeNow = _clock->TimeInMilliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000742
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000743 std::map<uint32_t, RTCPReceiveInformation*>::iterator receiveInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000744 _receivedInfoMap.begin();
niklase@google.com470e71d2011-07-07 08:21:25 +0000745
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000746 while (receiveInfoIt != _receivedInfoMap.end()) {
747 RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
748 if (receiveInfo == NULL) {
749 return updateBoundingSet;
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000751 // time since last received rtcp packet
752 // when we dont have a lastTimeReceived and the object is marked
753 // readyForDelete it's removed from the map
754 if (receiveInfo->lastTimeReceived) {
755 /// use audio define since we don't know what interval the remote peer is
756 // using
757 if ((timeNow - receiveInfo->lastTimeReceived) >
758 5 * RTCP_INTERVAL_AUDIO_MS) {
759 // no rtcp packet for the last five regular intervals, reset limitations
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000760 receiveInfo->TmmbrSet.clearSet();
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000761 // prevent that we call this over and over again
762 receiveInfo->lastTimeReceived = 0;
763 // send new TMMBN to all channels using the default codec
764 updateBoundingSet = true;
765 }
766 receiveInfoIt++;
767 } else if (receiveInfo->readyForDelete) {
768 // store our current receiveInfoItem
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000769 std::map<uint32_t, RTCPReceiveInformation*>::iterator
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000770 receiveInfoItemToBeErased = receiveInfoIt;
771 receiveInfoIt++;
772 delete receiveInfoItemToBeErased->second;
773 _receivedInfoMap.erase(receiveInfoItemToBeErased);
774 } else {
775 receiveInfoIt++;
776 }
777 }
778 return updateBoundingSet;
niklase@google.com470e71d2011-07-07 08:21:25 +0000779}
780
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000781int32_t RTCPReceiver::BoundingSet(bool &tmmbrOwner, TMMBRSet* boundingSetRec) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000782 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000783
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000784 std::map<uint32_t, RTCPReceiveInformation*>::iterator receiveInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000785 _receivedInfoMap.find(_remoteSSRC);
786
787 if (receiveInfoIt == _receivedInfoMap.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000788 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000789 }
790 RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
791 if (receiveInfo == NULL) {
792 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
793 "%s failed to get RTCPReceiveInformation",
794 __FUNCTION__);
795 return -1;
796 }
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000797 if (receiveInfo->TmmbnBoundingSet.lengthOfSet() > 0) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000798 boundingSetRec->VerifyAndAllocateSet(
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000799 receiveInfo->TmmbnBoundingSet.lengthOfSet() + 1);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000800 for(uint32_t i=0; i< receiveInfo->TmmbnBoundingSet.lengthOfSet();
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000801 i++) {
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000802 if(receiveInfo->TmmbnBoundingSet.Ssrc(i) == main_ssrc_) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000803 // owner of bounding set
804 tmmbrOwner = true;
805 }
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000806 boundingSetRec->SetEntry(i,
807 receiveInfo->TmmbnBoundingSet.Tmmbr(i),
808 receiveInfo->TmmbnBoundingSet.PacketOH(i),
809 receiveInfo->TmmbnBoundingSet.Ssrc(i));
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000810 }
811 }
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000812 return receiveInfo->TmmbnBoundingSet.lengthOfSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000813}
814
815// no need for critsect we have _criticalSectionRTCPReceiver
816void
817RTCPReceiver::HandleSDES(RTCPUtility::RTCPParserV2& rtcpParser)
818{
819 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
820 while (pktType == RTCPUtility::kRtcpSdesChunkCode)
821 {
822 HandleSDESChunk(rtcpParser);
823 pktType = rtcpParser.Iterate();
824 }
825}
826
827// no need for critsect we have _criticalSectionRTCPReceiver
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000828void RTCPReceiver::HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser) {
829 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
830 RTCPCnameInformation* cnameInfo =
831 CreateCnameInformation(rtcpPacket.CName.SenderSSRC);
832 assert(cnameInfo);
niklase@google.com470e71d2011-07-07 08:21:25 +0000833
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000834 cnameInfo->name[RTCP_CNAME_SIZE - 1] = 0;
835 strncpy(cnameInfo->name, rtcpPacket.CName.CName, RTCP_CNAME_SIZE - 1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000836}
837
838// no need for critsect we have _criticalSectionRTCPReceiver
839void
840RTCPReceiver::HandleNACK(RTCPUtility::RTCPParserV2& rtcpParser,
841 RTCPPacketInformation& rtcpPacketInformation)
842{
843 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000844 if (main_ssrc_ != rtcpPacket.NACK.MediaSSRC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 {
846 // Not to us.
847 rtcpParser.Iterate();
848 return;
849 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 rtcpPacketInformation.ResetNACKPacketIdArray();
851
852 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
853 while (pktType == RTCPUtility::kRtcpRtpfbNackItemCode)
854 {
855 HandleNACKItem(rtcpPacket, rtcpPacketInformation);
856 pktType = rtcpParser.Iterate();
857 }
858}
859
860// no need for critsect we have _criticalSectionRTCPReceiver
861void
862RTCPReceiver::HandleNACKItem(const RTCPUtility::RTCPPacket& rtcpPacket,
863 RTCPPacketInformation& rtcpPacketInformation)
864{
865 rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID);
866
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000867 uint16_t bitMask = rtcpPacket.NACKItem.BitMask;
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 if(bitMask)
869 {
870 for(int i=1; i <= 16; ++i)
871 {
872 if(bitMask & 0x01)
873 {
874 rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID + i);
875 }
876 bitMask = bitMask >>1;
877 }
878 }
879
880 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpNack;
881}
882
883// no need for critsect we have _criticalSectionRTCPReceiver
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000884void RTCPReceiver::HandleBYE(RTCPUtility::RTCPParserV2& rtcpParser) {
885 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000886
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000887 // clear our lists
888 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000889 std::map<uint32_t, RTCPReportBlockInformation*>::iterator
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000890 reportBlockInfoIt = _receivedReportBlockMap.find(
891 rtcpPacket.BYE.SenderSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000892
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000893 if (reportBlockInfoIt != _receivedReportBlockMap.end()) {
894 delete reportBlockInfoIt->second;
895 _receivedReportBlockMap.erase(reportBlockInfoIt);
896 }
897 // we can't delete it due to TMMBR
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000898 std::map<uint32_t, RTCPReceiveInformation*>::iterator receiveInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000899 _receivedInfoMap.find(rtcpPacket.BYE.SenderSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000900
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000901 if (receiveInfoIt != _receivedInfoMap.end()) {
902 receiveInfoIt->second->readyForDelete = true;
903 }
904
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000905 std::map<uint32_t, RTCPCnameInformation*>::iterator cnameInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000906 _receivedCnameMap.find(rtcpPacket.BYE.SenderSSRC);
907
908 if (cnameInfoIt != _receivedCnameMap.end()) {
909 delete cnameInfoIt->second;
910 _receivedCnameMap.erase(cnameInfoIt);
911 }
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000912 xr_rr_rtt_ms_ = 0;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000913 rtcpParser.Iterate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000914}
915
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000916void RTCPReceiver::HandleXrHeader(
917 RTCPUtility::RTCPParserV2& parser,
918 RTCPPacketInformation& rtcpPacketInformation) {
919 const RTCPUtility::RTCPPacket& packet = parser.Packet();
920
921 rtcpPacketInformation.xr_originator_ssrc = packet.XR.OriginatorSSRC;
922
923 parser.Iterate();
924}
925
926void RTCPReceiver::HandleXrReceiveReferenceTime(
927 RTCPUtility::RTCPParserV2& parser,
928 RTCPPacketInformation& rtcpPacketInformation) {
929 const RTCPUtility::RTCPPacket& packet = parser.Packet();
930
931 _remoteXRReceiveTimeInfo.sourceSSRC =
932 rtcpPacketInformation.xr_originator_ssrc;
933
934 _remoteXRReceiveTimeInfo.lastRR = RTCPUtility::MidNtp(
935 packet.XRReceiverReferenceTimeItem.NTPMostSignificant,
936 packet.XRReceiverReferenceTimeItem.NTPLeastSignificant);
937
938 _clock->CurrentNtp(_lastReceivedXRNTPsecs, _lastReceivedXRNTPfrac);
939
940 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
941
942 parser.Iterate();
943}
944
945void RTCPReceiver::HandleXrDlrrReportBlock(
946 RTCPUtility::RTCPParserV2& parser,
947 RTCPPacketInformation& rtcpPacketInformation) {
948 const RTCPUtility::RTCPPacket& packet = parser.Packet();
949 // Iterate through sub-block(s), if any.
950 RTCPUtility::RTCPPacketTypes packet_type = parser.Iterate();
951
952 while (packet_type == RTCPUtility::kRtcpXrDlrrReportBlockItemCode) {
953 HandleXrDlrrReportBlockItem(packet, rtcpPacketInformation);
954 packet_type = parser.Iterate();
955 }
956}
957
958void RTCPReceiver::HandleXrDlrrReportBlockItem(
959 const RTCPUtility::RTCPPacket& packet,
960 RTCPPacketInformation& rtcpPacketInformation) {
961 if (registered_ssrcs_.find(packet.XRDLRRReportBlockItem.SSRC) ==
962 registered_ssrcs_.end()) {
963 // Not to us.
964 return;
965 }
966
967 rtcpPacketInformation.xr_dlrr_item = true;
968
969 // To avoid problem with acquiring _criticalSectionRTCPSender while holding
970 // _criticalSectionRTCPReceiver.
971 _criticalSectionRTCPReceiver->Leave();
972
973 int64_t send_time_ms;
974 bool found = _rtpRtcp.SendTimeOfXrRrReport(
975 packet.XRDLRRReportBlockItem.LastRR, &send_time_ms);
976
977 _criticalSectionRTCPReceiver->Enter();
978
979 if (!found) {
980 return;
981 }
982
983 // The DelayLastRR field is in units of 1/65536 sec.
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000984 uint32_t delay_rr_ms =
985 (((packet.XRDLRRReportBlockItem.DelayLastRR & 0x0000ffff) * 1000) >> 16) +
986 (((packet.XRDLRRReportBlockItem.DelayLastRR & 0xffff0000) >> 16) * 1000);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000987
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000988 int32_t rtt = _clock->CurrentNtpInMilliseconds() - delay_rr_ms - send_time_ms;
989
990 xr_rr_rtt_ms_ = static_cast<uint16_t>(std::max(rtt, 1));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000991
992 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
993}
994
niklase@google.com470e71d2011-07-07 08:21:25 +0000995// no need for critsect we have _criticalSectionRTCPReceiver
996void
997RTCPReceiver::HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
998 RTCPPacketInformation& rtcpPacketInformation)
999{
1000 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1001
1002 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
1003
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001004 if(rtcpPacket.XRVOIPMetricItem.SSRC == main_ssrc_)
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 {
1006 // Store VoIP metrics block if it's about me
1007 // from OriginatorSSRC do we filter it?
1008 // rtcpPacket.XR.OriginatorSSRC;
1009
1010 RTCPVoIPMetric receivedVoIPMetrics;
1011 receivedVoIPMetrics.burstDensity = rtcpPacket.XRVOIPMetricItem.burstDensity;
1012 receivedVoIPMetrics.burstDuration = rtcpPacket.XRVOIPMetricItem.burstDuration;
1013 receivedVoIPMetrics.discardRate = rtcpPacket.XRVOIPMetricItem.discardRate;
1014 receivedVoIPMetrics.endSystemDelay = rtcpPacket.XRVOIPMetricItem.endSystemDelay;
1015 receivedVoIPMetrics.extRfactor = rtcpPacket.XRVOIPMetricItem.extRfactor;
1016 receivedVoIPMetrics.gapDensity = rtcpPacket.XRVOIPMetricItem.gapDensity;
1017 receivedVoIPMetrics.gapDuration = rtcpPacket.XRVOIPMetricItem.gapDuration;
1018 receivedVoIPMetrics.Gmin = rtcpPacket.XRVOIPMetricItem.Gmin;
1019 receivedVoIPMetrics.JBabsMax = rtcpPacket.XRVOIPMetricItem.JBabsMax;
1020 receivedVoIPMetrics.JBmax = rtcpPacket.XRVOIPMetricItem.JBmax;
1021 receivedVoIPMetrics.JBnominal = rtcpPacket.XRVOIPMetricItem.JBnominal;
1022 receivedVoIPMetrics.lossRate = rtcpPacket.XRVOIPMetricItem.lossRate;
1023 receivedVoIPMetrics.MOSCQ = rtcpPacket.XRVOIPMetricItem.MOSCQ;
1024 receivedVoIPMetrics.MOSLQ = rtcpPacket.XRVOIPMetricItem.MOSLQ;
1025 receivedVoIPMetrics.noiseLevel = rtcpPacket.XRVOIPMetricItem.noiseLevel;
1026 receivedVoIPMetrics.RERL = rtcpPacket.XRVOIPMetricItem.RERL;
1027 receivedVoIPMetrics.Rfactor = rtcpPacket.XRVOIPMetricItem.Rfactor;
1028 receivedVoIPMetrics.roundTripDelay = rtcpPacket.XRVOIPMetricItem.roundTripDelay;
1029 receivedVoIPMetrics.RXconfig = rtcpPacket.XRVOIPMetricItem.RXconfig;
1030 receivedVoIPMetrics.signalLevel = rtcpPacket.XRVOIPMetricItem.signalLevel;
1031
1032 rtcpPacketInformation.AddVoIPMetric(&receivedVoIPMetrics);
1033
1034 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrVoipMetric; // received signal
1035 }
1036 rtcpParser.Iterate();
1037}
1038
1039// no need for critsect we have _criticalSectionRTCPReceiver
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001040void RTCPReceiver::HandlePLI(RTCPUtility::RTCPParserV2& rtcpParser,
1041 RTCPPacketInformation& rtcpPacketInformation) {
1042 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001043 if (main_ssrc_ == rtcpPacket.PLI.MediaSSRC) {
justinlin@chromium.org7bfb3a32013-05-13 22:59:00 +00001044 TRACE_EVENT_INSTANT0("webrtc_rtp", "PLI");
1045
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001046 // Received a signal that we need to send a new key frame.
1047 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli;
1048 }
1049 rtcpParser.Iterate();
niklase@google.com470e71d2011-07-07 08:21:25 +00001050}
1051
1052// no need for critsect we have _criticalSectionRTCPReceiver
1053void
1054RTCPReceiver::HandleTMMBR(RTCPUtility::RTCPParserV2& rtcpParser,
1055 RTCPPacketInformation& rtcpPacketInformation)
1056{
1057 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1058
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001059 uint32_t senderSSRC = rtcpPacket.TMMBR.SenderSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00001060 RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(senderSSRC);
1061 if (ptrReceiveInfo == NULL)
1062 {
1063 // This remote SSRC must be saved before.
1064 rtcpParser.Iterate();
1065 return;
1066 }
1067 if(rtcpPacket.TMMBR.MediaSSRC)
1068 {
1069 // rtcpPacket.TMMBR.MediaSSRC SHOULD be 0 if same as SenderSSRC
1070 // in relay mode this is a valid number
1071 senderSSRC = rtcpPacket.TMMBR.MediaSSRC;
1072 }
1073
1074 // Use packet length to calc max number of TMMBR blocks
1075 // each TMMBR block is 8 bytes
1076 ptrdiff_t maxNumOfTMMBRBlocks = rtcpParser.LengthLeft() / 8;
1077
1078 // sanity
1079 if(maxNumOfTMMBRBlocks > 200) // we can't have more than what's in one packet
1080 {
1081 assert(false);
1082 rtcpParser.Iterate();
1083 return;
1084 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001085 ptrReceiveInfo->VerifyAndAllocateTMMBRSet((uint32_t)maxNumOfTMMBRBlocks);
niklase@google.com470e71d2011-07-07 08:21:25 +00001086
1087 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1088 while (pktType == RTCPUtility::kRtcpRtpfbTmmbrItemCode)
1089 {
1090 HandleTMMBRItem(*ptrReceiveInfo, rtcpPacket, rtcpPacketInformation, senderSSRC);
1091 pktType = rtcpParser.Iterate();
1092 }
1093}
1094
1095// no need for critsect we have _criticalSectionRTCPReceiver
1096void
1097RTCPReceiver::HandleTMMBRItem(RTCPReceiveInformation& receiveInfo,
1098 const RTCPUtility::RTCPPacket& rtcpPacket,
1099 RTCPPacketInformation& rtcpPacketInformation,
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001100 const uint32_t senderSSRC)
niklase@google.com470e71d2011-07-07 08:21:25 +00001101{
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001102 if (main_ssrc_ == rtcpPacket.TMMBRItem.SSRC &&
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 rtcpPacket.TMMBRItem.MaxTotalMediaBitRate > 0)
1104 {
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +00001105 receiveInfo.InsertTMMBRItem(senderSSRC, rtcpPacket.TMMBRItem,
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001106 _clock->TimeInMilliseconds());
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbr;
1108 }
1109}
1110
1111// no need for critsect we have _criticalSectionRTCPReceiver
1112void
hta@webrtc.org9d54cd12012-04-30 08:24:55 +00001113RTCPReceiver::HandleTMMBN(RTCPUtility::RTCPParserV2& rtcpParser,
1114 RTCPPacketInformation& rtcpPacketInformation)
niklase@google.com470e71d2011-07-07 08:21:25 +00001115{
1116 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1117 RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(rtcpPacket.TMMBN.SenderSSRC);
1118 if (ptrReceiveInfo == NULL)
1119 {
1120 // This remote SSRC must be saved before.
1121 rtcpParser.Iterate();
1122 return;
1123 }
hta@webrtc.org9d54cd12012-04-30 08:24:55 +00001124 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbn;
niklase@google.com470e71d2011-07-07 08:21:25 +00001125 // Use packet length to calc max number of TMMBN blocks
1126 // each TMMBN block is 8 bytes
1127 ptrdiff_t maxNumOfTMMBNBlocks = rtcpParser.LengthLeft() / 8;
1128
1129 // sanity
1130 if(maxNumOfTMMBNBlocks > 200) // we cant have more than what's in one packet
1131 {
1132 assert(false);
1133 rtcpParser.Iterate();
1134 return;
1135 }
1136
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001137 ptrReceiveInfo->VerifyAndAllocateBoundingSet((uint32_t)maxNumOfTMMBNBlocks);
niklase@google.com470e71d2011-07-07 08:21:25 +00001138
1139 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1140 while (pktType == RTCPUtility::kRtcpRtpfbTmmbnItemCode)
1141 {
1142 HandleTMMBNItem(*ptrReceiveInfo, rtcpPacket);
1143 pktType = rtcpParser.Iterate();
1144 }
1145}
1146
1147// no need for critsect we have _criticalSectionRTCPReceiver
1148void
1149RTCPReceiver::HandleSR_REQ(RTCPUtility::RTCPParserV2& rtcpParser,
1150 RTCPPacketInformation& rtcpPacketInformation)
1151{
1152 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSrReq;
1153 rtcpParser.Iterate();
1154}
1155
1156// no need for critsect we have _criticalSectionRTCPReceiver
1157void
1158RTCPReceiver::HandleTMMBNItem(RTCPReceiveInformation& receiveInfo,
1159 const RTCPUtility::RTCPPacket& rtcpPacket)
1160{
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001161 receiveInfo.TmmbnBoundingSet.AddEntry(
1162 rtcpPacket.TMMBNItem.MaxTotalMediaBitRate,
1163 rtcpPacket.TMMBNItem.MeasuredOverhead,
1164 rtcpPacket.TMMBNItem.SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001165}
1166
1167// no need for critsect we have _criticalSectionRTCPReceiver
1168void
1169RTCPReceiver::HandleSLI(RTCPUtility::RTCPParserV2& rtcpParser,
1170 RTCPPacketInformation& rtcpPacketInformation)
1171{
1172 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001173 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1174 while (pktType == RTCPUtility::kRtcpPsfbSliItemCode)
1175 {
1176 HandleSLIItem(rtcpPacket, rtcpPacketInformation);
1177 pktType = rtcpParser.Iterate();
1178 }
1179}
1180
1181// no need for critsect we have _criticalSectionRTCPReceiver
1182void
1183RTCPReceiver::HandleSLIItem(const RTCPUtility::RTCPPacket& rtcpPacket,
1184 RTCPPacketInformation& rtcpPacketInformation)
1185{
1186 // in theory there could be multiple slices lost
1187 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSli; // received signal that we need to refresh a slice
1188 rtcpPacketInformation.sliPictureId = rtcpPacket.SLIItem.PictureId;
1189}
1190
1191void
1192RTCPReceiver::HandleRPSI(RTCPUtility::RTCPParserV2& rtcpParser,
1193 RTCPHelp::RTCPPacketInformation& rtcpPacketInformation)
1194{
1195 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001196 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1197 if(pktType == RTCPUtility::kRtcpPsfbRpsiCode)
1198 {
1199 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRpsi; // received signal that we have a confirmed reference picture
1200 if(rtcpPacket.RPSI.NumberOfValidBits%8 != 0)
1201 {
1202 // to us unknown
1203 // continue
1204 rtcpParser.Iterate();
1205 return;
1206 }
1207 rtcpPacketInformation.rpsiPictureId = 0;
1208
1209 // convert NativeBitString to rpsiPictureId
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001210 uint8_t numberOfBytes = rtcpPacket.RPSI.NumberOfValidBits /8;
1211 for(uint8_t n = 0; n < (numberOfBytes-1); n++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 {
1213 rtcpPacketInformation.rpsiPictureId += (rtcpPacket.RPSI.NativeBitString[n] & 0x7f);
1214 rtcpPacketInformation.rpsiPictureId <<= 7; // prepare next
1215 }
1216 rtcpPacketInformation.rpsiPictureId += (rtcpPacket.RPSI.NativeBitString[numberOfBytes-1] & 0x7f);
1217 }
1218}
1219
1220// no need for critsect we have _criticalSectionRTCPReceiver
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001221void RTCPReceiver::HandlePsfbApp(RTCPUtility::RTCPParserV2& rtcpParser,
1222 RTCPPacketInformation& rtcpPacketInformation) {
1223 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1224 if (pktType == RTCPUtility::kRtcpPsfbRembCode) {
1225 pktType = rtcpParser.Iterate();
1226 if (pktType == RTCPUtility::kRtcpPsfbRembItemCode) {
1227 HandleREMBItem(rtcpParser, rtcpPacketInformation);
1228 rtcpParser.Iterate();
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001229 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001230 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001231}
1232
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001233// no need for critsect we have _criticalSectionRTCPReceiver
1234void
1235RTCPReceiver::HandleIJ(RTCPUtility::RTCPParserV2& rtcpParser,
1236 RTCPPacketInformation& rtcpPacketInformation)
1237{
1238 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1239
1240 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1241 while (pktType == RTCPUtility::kRtcpExtendedIjItemCode)
1242 {
1243 HandleIJItem(rtcpPacket, rtcpPacketInformation);
1244 pktType = rtcpParser.Iterate();
1245 }
1246}
1247
1248void
1249RTCPReceiver::HandleIJItem(const RTCPUtility::RTCPPacket& rtcpPacket,
1250 RTCPPacketInformation& rtcpPacketInformation)
1251{
1252 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1253 rtcpPacketInformation.interArrivalJitter =
1254 rtcpPacket.ExtendedJitterReportItem.Jitter;
1255}
1256
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001257void RTCPReceiver::HandleREMBItem(
1258 RTCPUtility::RTCPParserV2& rtcpParser,
1259 RTCPPacketInformation& rtcpPacketInformation) {
1260 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1261 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRemb;
1262 rtcpPacketInformation.receiverEstimatedMaxBitrate =
1263 rtcpPacket.REMBItem.BitRate;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001264}
1265
1266// no need for critsect we have _criticalSectionRTCPReceiver
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001267void RTCPReceiver::HandleFIR(RTCPUtility::RTCPParserV2& rtcpParser,
1268 RTCPPacketInformation& rtcpPacketInformation) {
1269 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1270 RTCPReceiveInformation* ptrReceiveInfo =
1271 GetReceiveInformation(rtcpPacket.FIR.SenderSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001272
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001273 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1274 while (pktType == RTCPUtility::kRtcpPsfbFirItemCode) {
1275 HandleFIRItem(ptrReceiveInfo, rtcpPacket, rtcpPacketInformation);
1276 pktType = rtcpParser.Iterate();
1277 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001278}
1279
1280// no need for critsect we have _criticalSectionRTCPReceiver
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001281void RTCPReceiver::HandleFIRItem(RTCPReceiveInformation* receiveInfo,
1282 const RTCPUtility::RTCPPacket& rtcpPacket,
1283 RTCPPacketInformation& rtcpPacketInformation) {
1284 // Is it our sender that is requested to generate a new keyframe
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001285 if (main_ssrc_ != rtcpPacket.FIRItem.SSRC) {
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001286 return;
1287 }
1288 // rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it
1289 // we don't know who this originate from
1290 if (receiveInfo) {
1291 // check if we have reported this FIRSequenceNumber before
1292 if (rtcpPacket.FIRItem.CommandSequenceNumber !=
1293 receiveInfo->lastFIRSequenceNumber) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001294 int64_t now = _clock->TimeInMilliseconds();
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001295 // sanity; don't go crazy with the callbacks
1296 if ((now - receiveInfo->lastFIRRequest) > RTCP_MIN_FRAME_LENGTH_MS) {
1297 receiveInfo->lastFIRRequest = now;
1298 receiveInfo->lastFIRSequenceNumber =
1299 rtcpPacket.FIRItem.CommandSequenceNumber;
1300 // received signal that we need to send a new key frame
1301 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir;
1302 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001303 }
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001304 } else {
1305 // received signal that we need to send a new key frame
1306 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir;
1307 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001308}
1309
1310void
1311RTCPReceiver::HandleAPP(RTCPUtility::RTCPParserV2& rtcpParser,
1312 RTCPPacketInformation& rtcpPacketInformation)
1313{
1314 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1315
1316 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpApp;
1317 rtcpPacketInformation.applicationSubType = rtcpPacket.APP.SubType;
1318 rtcpPacketInformation.applicationName = rtcpPacket.APP.Name;
1319
1320 rtcpParser.Iterate();
1321}
1322
1323void
1324RTCPReceiver::HandleAPPItem(RTCPUtility::RTCPParserV2& rtcpParser,
1325 RTCPPacketInformation& rtcpPacketInformation)
1326{
1327 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1328
1329 rtcpPacketInformation.AddApplicationData(rtcpPacket.APP.Data, rtcpPacket.APP.Size);
1330
1331 rtcpParser.Iterate();
1332}
1333
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001334int32_t RTCPReceiver::UpdateTMMBR() {
1335 int32_t numBoundingSet = 0;
1336 uint32_t bitrate = 0;
1337 uint32_t accNumCandidates = 0;
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00001338
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001339 int32_t size = TMMBRReceived(0, 0, NULL);
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00001340 if (size > 0) {
1341 TMMBRSet* candidateSet = VerifyAndAllocateCandidateSet(size);
1342 // Get candidate set from receiver.
1343 accNumCandidates = TMMBRReceived(size, accNumCandidates, candidateSet);
1344 } else {
1345 // Candidate set empty.
1346 VerifyAndAllocateCandidateSet(0); // resets candidate set
1347 }
1348 // Find bounding set
1349 TMMBRSet* boundingSet = NULL;
1350 numBoundingSet = FindTMMBRBoundingSet(boundingSet);
1351 if (numBoundingSet == -1) {
1352 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
1353 "Failed to find TMMBR bounding set.");
1354 return -1;
1355 }
1356 // Set bounding set
1357 // Inform remote clients about the new bandwidth
1358 // inform the remote client
1359 _rtpRtcp.SetTMMBN(boundingSet);
1360
1361 // might trigger a TMMBN
1362 if (numBoundingSet == 0) {
1363 // owner of max bitrate request has timed out
1364 // empty bounding set has been sent
1365 return 0;
1366 }
1367 // Get net bitrate from bounding set depending on sent packet rate
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001368 if (CalcMinBitRate(&bitrate)) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00001369 // we have a new bandwidth estimate on this channel
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001370 CriticalSectionScoped lock(_criticalSectionFeedbacks);
1371 if (_cbRtcpBandwidthObserver) {
1372 _cbRtcpBandwidthObserver->OnReceivedEstimatedBitrate(bitrate * 1000);
1373 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
1374 "Set TMMBR request:%d kbps", bitrate);
1375 }
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00001376 }
1377 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001378}
1379
1380// Holding no Critical section
pwestin@webrtc.org3aa25de2012-01-05 08:40:56 +00001381void RTCPReceiver::TriggerCallbacksFromRTCPPacket(
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001382 RTCPPacketInformation& rtcpPacketInformation) {
1383 // Process TMMBR and REMB first to avoid multiple callbacks
1384 // to OnNetworkChanged.
1385 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr) {
1386 WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
1387 "SIG [RTCP] Incoming TMMBR to id:%d", _id);
pwestin@webrtc.org3aa25de2012-01-05 08:40:56 +00001388
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001389 // Might trigger a OnReceivedBandwidthEstimateUpdate.
1390 UpdateTMMBR();
1391 }
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001392 unsigned int local_ssrc = 0;
1393 {
1394 // We don't want to hold this critsect when triggering the callbacks below.
1395 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001396 local_ssrc = main_ssrc_;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001397 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001398 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSrReq) {
1399 _rtpRtcp.OnRequestSendReport();
1400 }
1401 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
stefan@webrtc.orgbecf9c82013-02-01 15:09:57 +00001402 if (rtcpPacketInformation.nackSequenceNumbers.size() > 0) {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001403 WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
1404 "SIG [RTCP] Incoming NACK length:%d",
stefan@webrtc.orgbecf9c82013-02-01 15:09:57 +00001405 rtcpPacketInformation.nackSequenceNumbers.size());
1406 _rtpRtcp.OnReceivedNACK(rtcpPacketInformation.nackSequenceNumbers);
pwestin@webrtc.org3aa25de2012-01-05 08:40:56 +00001407 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001408 }
1409 {
1410 CriticalSectionScoped lock(_criticalSectionFeedbacks);
pwestin@webrtc.org3aa25de2012-01-05 08:40:56 +00001411
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001412 // We need feedback that we have received a report block(s) so that we
1413 // can generate a new packet in a conference relay scenario, one received
1414 // report can generate several RTCP packets, based on number relayed/mixed
1415 // a send report block should go out to all receivers.
1416 if (_cbRtcpIntraFrameObserver) {
1417 if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) ||
1418 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpFir)) {
1419 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) {
1420 WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
1421 "SIG [RTCP] Incoming PLI from SSRC:0x%x",
1422 rtcpPacketInformation.remoteSSRC);
1423 } else {
1424 WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
1425 "SIG [RTCP] Incoming FIR from SSRC:0x%x",
1426 rtcpPacketInformation.remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 }
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001428 _cbRtcpIntraFrameObserver->OnReceivedIntraFrameRequest(local_ssrc);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001429 }
1430 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSli) {
1431 _cbRtcpIntraFrameObserver->OnReceivedSLI(
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001432 local_ssrc, rtcpPacketInformation.sliPictureId);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001433 }
1434 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRpsi) {
1435 _cbRtcpIntraFrameObserver->OnReceivedRPSI(
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001436 local_ssrc, rtcpPacketInformation.rpsiPictureId);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001437 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001438 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001439 if (_cbRtcpBandwidthObserver) {
1440 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb) {
1441 WEBRTC_TRACE(kTraceStateInfo, kTraceRtpRtcp, _id,
1442 "SIG [RTCP] Incoming REMB:%d",
1443 rtcpPacketInformation.receiverEstimatedMaxBitrate);
1444 _cbRtcpBandwidthObserver->OnReceivedEstimatedBitrate(
1445 rtcpPacketInformation.receiverEstimatedMaxBitrate);
1446 }
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001447 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr ||
1448 rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRr) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001449 int64_t now = _clock->TimeInMilliseconds();
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001450 _cbRtcpBandwidthObserver->OnReceivedRtcpReceiverReport(
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001451 rtcpPacketInformation.report_blocks,
1452 rtcpPacketInformation.rtt,
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001453 now);
1454 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001455 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001456 if(_cbRtcpFeedback) {
solenberg@webrtc.org91811e22013-06-25 20:36:14 +00001457 if(!(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr)) {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001458 _cbRtcpFeedback->OnReceiveReportReceived(_id,
1459 rtcpPacketInformation.remoteSSRC);
1460 }
1461 if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpXrVoipMetric) {
1462 _cbRtcpFeedback->OnXRVoIPMetricReceived(_id,
1463 rtcpPacketInformation.VoIPMetric);
1464 }
1465 if(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpApp) {
1466 _cbRtcpFeedback->OnApplicationDataReceived(_id,
1467 rtcpPacketInformation.applicationSubType,
1468 rtcpPacketInformation.applicationName,
1469 rtcpPacketInformation.applicationLength,
1470 rtcpPacketInformation.applicationData);
1471 }
1472 }
1473 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001474}
1475
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001476int32_t RTCPReceiver::CNAME(const uint32_t remoteSSRC,
1477 char cName[RTCP_CNAME_SIZE]) const {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001478 assert(cName);
1479
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00001480 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
1481 RTCPCnameInformation* cnameInfo = GetCnameInformation(remoteSSRC);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001482 if (cnameInfo == NULL) {
1483 return -1;
1484 }
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00001485 cName[RTCP_CNAME_SIZE - 1] = 0;
1486 strncpy(cName, cnameInfo->name, RTCP_CNAME_SIZE - 1);
1487 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001488}
1489
1490// no callbacks allowed inside this function
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001491int32_t RTCPReceiver::TMMBRReceived(const uint32_t size,
1492 const uint32_t accNumCandidates,
1493 TMMBRSet* candidateSet) const {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001494 CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +00001495
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001496 std::map<uint32_t, RTCPReceiveInformation*>::const_iterator
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001497 receiveInfoIt = _receivedInfoMap.begin();
1498 if (receiveInfoIt == _receivedInfoMap.end()) {
1499 return -1;
1500 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001501 uint32_t num = accNumCandidates;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001502 if (candidateSet) {
1503 while( num < size && receiveInfoIt != _receivedInfoMap.end()) {
1504 RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
1505 if (receiveInfo == NULL) {
1506 return 0;
1507 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001508 for (uint32_t i = 0;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001509 (num < size) && (i < receiveInfo->TmmbrSet.lengthOfSet()); i++) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001510 if (receiveInfo->GetTMMBRSet(i, num, candidateSet,
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001511 _clock->TimeInMilliseconds()) == 0) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001512 num++;
1513 }
1514 }
1515 receiveInfoIt++;
1516 }
1517 } else {
1518 while (receiveInfoIt != _receivedInfoMap.end()) {
1519 RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
1520 if(receiveInfo == NULL) {
1521 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
1522 "%s failed to get RTCPReceiveInformation",
1523 __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001525 }
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001526 num += receiveInfo->TmmbrSet.lengthOfSet();
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001527 receiveInfoIt++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001528 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001529 }
1530 return num;
niklase@google.com470e71d2011-07-07 08:21:25 +00001531}
1532
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001533} // namespace webrtc