blob: 0192d624dd69da21f875c96b52391867413d131b [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
Peter Boströmfe7a80c2015-04-23 17:53:17 +020013#include <assert.h>
14#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000015
danilchap2f69ce92016-08-16 03:21:38 -070016#include <limits>
17
Peter Boströmfe7a80c2015-04-23 17:53:17 +020018#include "webrtc/base/checks.h"
Peter Boströmebc0b4e2015-10-28 16:39:33 +010019#include "webrtc/base/logging.h"
tommie4f96502015-10-20 23:00:48 -070020#include "webrtc/base/trace_event.h"
Erik Språng6b8d3552015-09-24 15:06:57 +020021#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
tommie4f96502015-10-20 23:00:48 -070022#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
Danil Chapovalova094fd12016-02-22 18:59:36 +010023#include "webrtc/modules/rtp_rtcp/source/time_util.h"
danilchap13deaad2016-05-24 13:25:27 -070024#include "webrtc/modules/rtp_rtcp/source/tmmbr_help.h"
Danil Chapovalova094fd12016-02-22 18:59:36 +010025#include "webrtc/system_wrappers/include/ntp_time.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
niklase@google.com470e71d2011-07-07 08:21:25 +000027namespace webrtc {
danilchap6a6f0892015-12-10 12:39:08 -080028using RTCPHelp::RTCPPacketInformation;
29using RTCPHelp::RTCPReceiveInformation;
30using RTCPHelp::RTCPReportBlockInformation;
31using RTCPUtility::kBtVoipMetric;
32using RTCPUtility::RTCPCnameInformation;
33using RTCPUtility::RTCPPacketReportBlockItem;
34using RTCPUtility::RTCPPacketTypes;
niklase@google.com470e71d2011-07-07 08:21:25 +000035
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +000036// The number of RTCP time intervals needed to trigger a timeout.
37const int kRrTimeoutIntervals = 3;
38
Erik Språng6b8d3552015-09-24 15:06:57 +020039const int64_t kMaxWarningLogIntervalMs = 10000;
40
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +000041RTCPReceiver::RTCPReceiver(
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +000042 Clock* clock,
Peter Boströmfe7a80c2015-04-23 17:53:17 +020043 bool receiver_only,
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +000044 RtcpPacketTypeCounterObserver* packet_type_counter_observer,
mflodman@webrtc.org96abda02015-02-25 13:50:10 +000045 RtcpBandwidthObserver* rtcp_bandwidth_observer,
46 RtcpIntraFrameObserver* rtcp_intra_frame_observer,
Erik Språng6b8d3552015-09-24 15:06:57 +020047 TransportFeedbackObserver* transport_feedback_observer,
danilchap59cb2bd2016-08-29 11:08:47 -070048 ModuleRtpRtcp* owner)
danilchap13deaad2016-05-24 13:25:27 -070049 : _clock(clock),
Peter Boströmfe7a80c2015-04-23 17:53:17 +020050 receiver_only_(receiver_only),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000051 _lastReceived(0),
52 _rtpRtcp(*owner),
mflodman@webrtc.org96abda02015-02-25 13:50:10 +000053 _cbRtcpBandwidthObserver(rtcp_bandwidth_observer),
54 _cbRtcpIntraFrameObserver(rtcp_intra_frame_observer),
Erik Språng6b8d3552015-09-24 15:06:57 +020055 _cbTransportFeedbackObserver(transport_feedback_observer),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000056 main_ssrc_(0),
57 _remoteSSRC(0),
58 _remoteSenderInfo(),
59 _lastReceivedSRNTPsecs(0),
60 _lastReceivedSRNTPfrac(0),
61 _lastReceivedXRNTPsecs(0),
62 _lastReceivedXRNTPfrac(0),
Danil Chapovalovc1e55c72016-03-09 15:14:35 +010063 xr_rrtr_status_(false),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000064 xr_rr_rtt_ms_(0),
65 _receivedInfoMap(),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000066 _lastReceivedRrMs(0),
67 _lastIncreasedSequenceNumberMs(0),
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +000068 stats_callback_(NULL),
Erik Språng6b8d3552015-09-24 15:06:57 +020069 packet_type_counter_observer_(packet_type_counter_observer),
70 num_skipped_packets_(0),
71 last_skipped_packets_warning_(clock->TimeInMilliseconds()) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +000072 memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000075RTCPReceiver::~RTCPReceiver() {
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +000076 ReportBlockMap::iterator it = _receivedReportBlockMap.begin();
77 for (; it != _receivedReportBlockMap.end(); ++it) {
78 ReportBlockInfoMap* info_map = &(it->second);
79 while (!info_map->empty()) {
80 ReportBlockInfoMap::iterator it_info = info_map->begin();
81 delete it_info->second;
82 info_map->erase(it_info);
83 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000084 }
85 while (!_receivedInfoMap.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +000086 std::map<uint32_t, RTCPReceiveInformation*>::iterator first =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000087 _receivedInfoMap.begin();
88 delete first->second;
89 _receivedInfoMap.erase(first);
90 }
91 while (!_receivedCnameMap.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +000092 std::map<uint32_t, RTCPCnameInformation*>::iterator first =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000093 _receivedCnameMap.begin();
94 delete first->second;
95 _receivedCnameMap.erase(first);
96 }
niklase@google.com470e71d2011-07-07 08:21:25 +000097}
98
danilchap59cb2bd2016-08-29 11:08:47 -070099bool RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) {
100 // Allow receive of non-compound RTCP packets.
101 RTCPUtility::RTCPParserV2 rtcp_parser(packet, packet_size, true);
102
103 if (!rtcp_parser.IsValid()) {
104 LOG(LS_WARNING) << "Incoming invalid RTCP packet";
105 return false;
106 }
107 RTCPHelp::RTCPPacketInformation rtcp_packet_information;
108 IncomingRTCPPacket(rtcp_packet_information, &rtcp_parser);
109 TriggerCallbacksFromRTCPPacket(rtcp_packet_information);
110 return true;
111}
112
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000113int64_t RTCPReceiver::LastReceived() {
danilchap7c9426c2016-04-14 03:05:31 -0700114 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000115 return _lastReceived;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000118int64_t RTCPReceiver::LastReceivedReceiverReport() const {
danilchap7c9426c2016-04-14 03:05:31 -0700119 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000120 int64_t last_received_rr = -1;
121 for (ReceivedInfoMap::const_iterator it = _receivedInfoMap.begin();
122 it != _receivedInfoMap.end(); ++it) {
danilchap2b616392016-08-18 06:17:42 -0700123 if (it->second->last_time_received_ms > last_received_rr) {
124 last_received_rr = it->second->last_time_received_ms;
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000125 }
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000126 }
127 return last_received_rr;
stefan@webrtc.orgb5865072013-02-01 14:33:42 +0000128}
129
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000130void RTCPReceiver::SetRemoteSSRC(uint32_t ssrc) {
danilchap7c9426c2016-04-14 03:05:31 -0700131 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000132
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000133 // new SSRC reset old reports
134 memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
135 _lastReceivedSRNTPsecs = 0;
136 _lastReceivedSRNTPfrac = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000137
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000138 _remoteSSRC = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000141uint32_t RTCPReceiver::RemoteSSRC() const {
danilchap7c9426c2016-04-14 03:05:31 -0700142 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000143 return _remoteSSRC;
144}
145
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000146void RTCPReceiver::SetSsrcs(uint32_t main_ssrc,
147 const std::set<uint32_t>& registered_ssrcs) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000148 uint32_t old_ssrc = 0;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000149 {
danilchap7c9426c2016-04-14 03:05:31 -0700150 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000151 old_ssrc = main_ssrc_;
152 main_ssrc_ = main_ssrc;
153 registered_ssrcs_ = registered_ssrcs;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000154 }
155 {
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000156 if (_cbRtcpIntraFrameObserver && old_ssrc != main_ssrc) {
157 _cbRtcpIntraFrameObserver->OnLocalSsrcChanged(old_ssrc, main_ssrc);
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +0000158 }
159 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000160}
161
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000162int32_t RTCPReceiver::RTT(uint32_t remoteSSRC,
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000163 int64_t* RTT,
164 int64_t* avgRTT,
165 int64_t* minRTT,
166 int64_t* maxRTT) const {
danilchap7c9426c2016-04-14 03:05:31 -0700167 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000168
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000169 RTCPReportBlockInformation* reportBlock =
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000170 GetReportBlockInformation(remoteSSRC, main_ssrc_);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000171
172 if (reportBlock == NULL) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000173 return -1;
174 }
175 if (RTT) {
176 *RTT = reportBlock->RTT;
177 }
178 if (avgRTT) {
179 *avgRTT = reportBlock->avgRTT;
180 }
181 if (minRTT) {
182 *minRTT = reportBlock->minRTT;
183 }
184 if (maxRTT) {
185 *maxRTT = reportBlock->maxRTT;
186 }
187 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000188}
189
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100190void RTCPReceiver::SetRtcpXrRrtrStatus(bool enable) {
danilchap7c9426c2016-04-14 03:05:31 -0700191 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100192 xr_rrtr_status_ = enable;
193}
194
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000195bool RTCPReceiver::GetAndResetXrRrRtt(int64_t* rtt_ms) {
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000196 assert(rtt_ms);
danilchap7c9426c2016-04-14 03:05:31 -0700197 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000198 if (xr_rr_rtt_ms_ == 0) {
199 return false;
200 }
201 *rtt_ms = xr_rr_rtt_ms_;
202 xr_rr_rtt_ms_ = 0;
203 return true;
204}
205
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000206// TODO(pbos): Make this fail when we haven't received NTP.
207bool RTCPReceiver::NTP(uint32_t* ReceivedNTPsecs,
208 uint32_t* ReceivedNTPfrac,
209 uint32_t* RTCPArrivalTimeSecs,
210 uint32_t* RTCPArrivalTimeFrac,
danilchapda161d72016-08-19 07:29:46 -0700211 uint32_t* rtcp_timestamp) const {
212 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
213 if (ReceivedNTPsecs) {
214 *ReceivedNTPsecs =
215 _remoteSenderInfo.NTPseconds; // NTP from incoming SendReport
216 }
217 if (ReceivedNTPfrac) {
218 *ReceivedNTPfrac = _remoteSenderInfo.NTPfraction;
219 }
220 if (RTCPArrivalTimeFrac) {
221 *RTCPArrivalTimeFrac = _lastReceivedSRNTPfrac; // local NTP time when we
222 // received a RTCP packet
223 // with a send block
224 }
225 if (RTCPArrivalTimeSecs) {
226 *RTCPArrivalTimeSecs = _lastReceivedSRNTPsecs;
227 }
228 if (rtcp_timestamp) {
229 *rtcp_timestamp = _remoteSenderInfo.RTPtimeStamp;
230 }
231 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000232}
233
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000234bool RTCPReceiver::LastReceivedXrReferenceTimeInfo(
235 RtcpReceiveTimeInfo* info) const {
236 assert(info);
danilchap7c9426c2016-04-14 03:05:31 -0700237 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000238 if (_lastReceivedXRNTPsecs == 0 && _lastReceivedXRNTPfrac == 0) {
239 return false;
240 }
241
242 info->sourceSSRC = _remoteXRReceiveTimeInfo.sourceSSRC;
243 info->lastRR = _remoteXRReceiveTimeInfo.lastRR;
244
245 // Get the delay since last received report (RFC 3611).
danilchapda161d72016-08-19 07:29:46 -0700246 uint32_t receive_time =
247 RTCPUtility::MidNtp(_lastReceivedXRNTPsecs, _lastReceivedXRNTPfrac);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000248
249 uint32_t ntp_sec = 0;
250 uint32_t ntp_frac = 0;
251 _clock->CurrentNtp(ntp_sec, ntp_frac);
252 uint32_t now = RTCPUtility::MidNtp(ntp_sec, ntp_frac);
253
254 info->delaySinceLastRR = now - receive_time;
255 return true;
256}
257
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000258int32_t RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const {
259 assert(senderInfo);
danilchap7c9426c2016-04-14 03:05:31 -0700260 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000261 if (_lastReceivedSRNTPsecs == 0) {
262 return -1;
263 }
264 memcpy(senderInfo, &(_remoteSenderInfo), sizeof(RTCPSenderInfo));
265 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
268// statistics
269// we can get multiple receive reports when we receive the report from a CE
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000270int32_t RTCPReceiver::StatisticsReceived(
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000271 std::vector<RTCPReportBlock>* receiveBlocks) const {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000272 assert(receiveBlocks);
danilchap7c9426c2016-04-14 03:05:31 -0700273 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000274 ReportBlockMap::const_iterator it = _receivedReportBlockMap.begin();
275 for (; it != _receivedReportBlockMap.end(); ++it) {
276 const ReportBlockInfoMap* info_map = &(it->second);
277 ReportBlockInfoMap::const_iterator it_info = info_map->begin();
278 for (; it_info != info_map->end(); ++it_info) {
279 receiveBlocks->push_back(it_info->second->remoteReceiveBlock);
280 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000281 }
282 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283}
284
danilchapda161d72016-08-19 07:29:46 -0700285int32_t RTCPReceiver::IncomingRTCPPacket(
286 RTCPPacketInformation& rtcpPacketInformation,
287 RTCPUtility::RTCPParserV2* rtcpParser) {
288 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000289
danilchapda161d72016-08-19 07:29:46 -0700290 _lastReceived = _clock->TimeInMilliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000291
danilchapda161d72016-08-19 07:29:46 -0700292 if (packet_type_counter_.first_packet_time_ms == -1) {
293 packet_type_counter_.first_packet_time_ms = _lastReceived;
294 }
295
296 RTCPUtility::RTCPPacketTypes pktType = rtcpParser->Begin();
297 while (pktType != RTCPPacketTypes::kInvalid) {
298 // Each "case" is responsible for iterate the parser to the
299 // next top level packet.
300 switch (pktType) {
301 case RTCPPacketTypes::kSr:
Danil Chapovalov91511f12016-09-15 16:24:02 +0200302 HandleSenderReport(*rtcpParser, rtcpPacketInformation);
303 break;
danilchapda161d72016-08-19 07:29:46 -0700304 case RTCPPacketTypes::kRr:
Danil Chapovalov91511f12016-09-15 16:24:02 +0200305 HandleReceiverReport(*rtcpParser, rtcpPacketInformation);
danilchapda161d72016-08-19 07:29:46 -0700306 break;
307 case RTCPPacketTypes::kSdes:
308 HandleSDES(*rtcpParser, rtcpPacketInformation);
309 break;
310 case RTCPPacketTypes::kXrHeader:
311 HandleXrHeader(*rtcpParser, rtcpPacketInformation);
312 break;
313 case RTCPPacketTypes::kXrReceiverReferenceTime:
314 HandleXrReceiveReferenceTime(*rtcpParser, rtcpPacketInformation);
315 break;
316 case RTCPPacketTypes::kXrDlrrReportBlock:
317 HandleXrDlrrReportBlock(*rtcpParser, rtcpPacketInformation);
318 break;
danilchapda161d72016-08-19 07:29:46 -0700319 case RTCPPacketTypes::kBye:
320 HandleBYE(*rtcpParser);
321 break;
322 case RTCPPacketTypes::kRtpfbNack:
323 HandleNACK(*rtcpParser, rtcpPacketInformation);
324 break;
325 case RTCPPacketTypes::kRtpfbTmmbr:
326 HandleTMMBR(*rtcpParser, rtcpPacketInformation);
327 break;
328 case RTCPPacketTypes::kRtpfbTmmbn:
329 HandleTMMBN(*rtcpParser, rtcpPacketInformation);
330 break;
331 case RTCPPacketTypes::kRtpfbSrReq:
332 HandleSR_REQ(*rtcpParser, rtcpPacketInformation);
333 break;
334 case RTCPPacketTypes::kPsfbPli:
335 HandlePLI(*rtcpParser, rtcpPacketInformation);
336 break;
337 case RTCPPacketTypes::kPsfbSli:
338 HandleSLI(*rtcpParser, rtcpPacketInformation);
339 break;
340 case RTCPPacketTypes::kPsfbRpsi:
341 HandleRPSI(*rtcpParser, rtcpPacketInformation);
342 break;
danilchapda161d72016-08-19 07:29:46 -0700343 case RTCPPacketTypes::kPsfbFir:
344 HandleFIR(*rtcpParser, rtcpPacketInformation);
345 break;
346 case RTCPPacketTypes::kPsfbApp:
347 HandlePsfbApp(*rtcpParser, rtcpPacketInformation);
348 break;
danilchapda161d72016-08-19 07:29:46 -0700349 case RTCPPacketTypes::kTransportFeedback:
350 HandleTransportFeedback(rtcpParser, &rtcpPacketInformation);
351 break;
352 default:
353 rtcpParser->Iterate();
354 break;
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000355 }
danilchapda161d72016-08-19 07:29:46 -0700356 pktType = rtcpParser->PacketType();
357 }
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000358
danilchapda161d72016-08-19 07:29:46 -0700359 if (packet_type_counter_observer_ != NULL) {
360 packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
361 main_ssrc_, packet_type_counter_);
362 }
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000363
danilchapda161d72016-08-19 07:29:46 -0700364 num_skipped_packets_ += rtcpParser->NumSkippedBlocks();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000365
danilchapda161d72016-08-19 07:29:46 -0700366 int64_t now = _clock->TimeInMilliseconds();
367 if (now - last_skipped_packets_warning_ >= kMaxWarningLogIntervalMs &&
368 num_skipped_packets_ > 0) {
369 last_skipped_packets_warning_ = now;
370 LOG(LS_WARNING) << num_skipped_packets_
371 << " RTCP blocks were skipped due to being malformed or of "
372 "unrecognized/unsupported type, during the past "
373 << (kMaxWarningLogIntervalMs / 1000) << " second period.";
374 }
Erik Språng6b8d3552015-09-24 15:06:57 +0200375
danilchapda161d72016-08-19 07:29:46 -0700376 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000377}
378
Danil Chapovalov91511f12016-09-15 16:24:02 +0200379void RTCPReceiver::HandleSenderReport(
danilchapda161d72016-08-19 07:29:46 -0700380 RTCPUtility::RTCPParserV2& rtcpParser,
381 RTCPPacketInformation& rtcpPacketInformation) {
382 RTCPUtility::RTCPPacketTypes rtcpPacketType = rtcpParser.PacketType();
383 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000384
Danil Chapovalov91511f12016-09-15 16:24:02 +0200385 RTC_DCHECK(rtcpPacketType == RTCPPacketTypes::kSr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000386
danilchapda161d72016-08-19 07:29:46 -0700387 // SR.SenderSSRC
388 // The synchronization source identifier for the originator of this SR packet
niklase@google.com470e71d2011-07-07 08:21:25 +0000389
Danil Chapovalov91511f12016-09-15 16:24:02 +0200390 const uint32_t remoteSSRC = rtcpPacket.SR.SenderSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +0000391
danilchapda161d72016-08-19 07:29:46 -0700392 rtcpPacketInformation.remoteSSRC = remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +0000393
danilchapda161d72016-08-19 07:29:46 -0700394 RTCPReceiveInformation* ptrReceiveInfo = CreateReceiveInformation(remoteSSRC);
395 if (!ptrReceiveInfo) {
396 rtcpParser.Iterate();
397 return;
398 }
399
Danil Chapovalov91511f12016-09-15 16:24:02 +0200400 TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "SR",
401 "remote_ssrc", remoteSSRC, "ssrc", main_ssrc_);
danilchapda161d72016-08-19 07:29:46 -0700402
Danil Chapovalov91511f12016-09-15 16:24:02 +0200403 // Have I received RTP packets from this party?
404 if (_remoteSSRC == remoteSSRC) {
405 // Only signal that we have received a SR when we accept one.
406 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSr;
danilchapda161d72016-08-19 07:29:46 -0700407
Danil Chapovalov91511f12016-09-15 16:24:02 +0200408 rtcpPacketInformation.ntp_secs = rtcpPacket.SR.NTPMostSignificant;
409 rtcpPacketInformation.ntp_frac = rtcpPacket.SR.NTPLeastSignificant;
410 rtcpPacketInformation.rtp_timestamp = rtcpPacket.SR.RTPTimestamp;
danilchapda161d72016-08-19 07:29:46 -0700411
Danil Chapovalov91511f12016-09-15 16:24:02 +0200412 // Save the NTP time of this report.
413 _remoteSenderInfo.NTPseconds = rtcpPacket.SR.NTPMostSignificant;
414 _remoteSenderInfo.NTPfraction = rtcpPacket.SR.NTPLeastSignificant;
415 _remoteSenderInfo.RTPtimeStamp = rtcpPacket.SR.RTPTimestamp;
416 _remoteSenderInfo.sendPacketCount = rtcpPacket.SR.SenderPacketCount;
417 _remoteSenderInfo.sendOctetCount = rtcpPacket.SR.SenderOctetCount;
danilchapda161d72016-08-19 07:29:46 -0700418
Danil Chapovalov91511f12016-09-15 16:24:02 +0200419 _clock->CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac);
danilchapda161d72016-08-19 07:29:46 -0700420 } else {
Danil Chapovalov91511f12016-09-15 16:24:02 +0200421 // We will only store the send report from one source, but
422 // we will store all the receive blocks.
danilchapda161d72016-08-19 07:29:46 -0700423 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
424 }
425 // Update that this remote is alive.
426 ptrReceiveInfo->last_time_received_ms = _clock->TimeInMilliseconds();
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000427
danilchapda161d72016-08-19 07:29:46 -0700428 rtcpPacketType = rtcpParser.Iterate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000429
danilchapda161d72016-08-19 07:29:46 -0700430 while (rtcpPacketType == RTCPPacketTypes::kReportBlockItem) {
431 HandleReportBlock(rtcpPacket, rtcpPacketInformation, remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 rtcpPacketType = rtcpParser.Iterate();
danilchapda161d72016-08-19 07:29:46 -0700433 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000434}
435
Danil Chapovalov91511f12016-09-15 16:24:02 +0200436void RTCPReceiver::HandleReceiverReport(
437 RTCPUtility::RTCPParserV2& rtcpParser,
438 RTCPPacketInformation& rtcpPacketInformation) {
439 RTCPUtility::RTCPPacketTypes rtcpPacketType = rtcpParser.PacketType();
440 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
441
442 RTC_DCHECK(rtcpPacketType == RTCPPacketTypes::kRr);
443
444 // rtcpPacket.RR.SenderSSRC
445 // The source of the packet sender, same as of SR? or is this a CE?
446 const uint32_t remoteSSRC = rtcpPacket.RR.SenderSSRC;
447
448 rtcpPacketInformation.remoteSSRC = remoteSSRC;
449
450 RTCPReceiveInformation* ptrReceiveInfo = CreateReceiveInformation(remoteSSRC);
451 if (!ptrReceiveInfo) {
452 rtcpParser.Iterate();
453 return;
454 }
455
456 TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RR",
457 "remote_ssrc", remoteSSRC, "ssrc", main_ssrc_);
458
459 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRr;
460
461 // Update that this remote is alive.
462 ptrReceiveInfo->last_time_received_ms = _clock->TimeInMilliseconds();
463
464 rtcpPacketType = rtcpParser.Iterate();
465
466 while (rtcpPacketType == RTCPPacketTypes::kReportBlockItem) {
467 HandleReportBlock(rtcpPacket, rtcpPacketInformation, remoteSSRC);
468 rtcpPacketType = rtcpParser.Iterate();
469 }
470}
471
andresp@webrtc.org7fb75ec2013-12-20 20:20:50 +0000472void RTCPReceiver::HandleReportBlock(
473 const RTCPUtility::RTCPPacket& rtcpPacket,
474 RTCPPacketInformation& rtcpPacketInformation,
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000475 uint32_t remoteSSRC)
andresp@webrtc.org7fb75ec2013-12-20 20:20:50 +0000476 EXCLUSIVE_LOCKS_REQUIRED(_criticalSectionRTCPReceiver) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000477 // This will be called once per report block in the RTCP packet.
478 // We filter out all report blocks that are not for us.
479 // Each packet has max 31 RR blocks.
480 //
481 // We can calc RTT if we send a send report and get a report block back.
niklase@google.com470e71d2011-07-07 08:21:25 +0000482
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000483 // |rtcpPacket.ReportBlockItem.SSRC| is the SSRC identifier of the source to
484 // which the information in this reception report block pertains.
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000486 // Filter out all report blocks that are not for us.
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000487 if (registered_ssrcs_.find(rtcpPacket.ReportBlockItem.SSRC) ==
488 registered_ssrcs_.end()) {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000489 // This block is not for us ignore it.
490 return;
491 }
492
danilchapda161d72016-08-19 07:29:46 -0700493 RTCPReportBlockInformation* reportBlock = CreateOrGetReportBlockInformation(
494 remoteSSRC, rtcpPacket.ReportBlockItem.SSRC);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000495 if (reportBlock == NULL) {
danilchapda161d72016-08-19 07:29:46 -0700496 LOG(LS_WARNING) << "Failed to CreateReportBlockInformation(" << remoteSSRC
497 << ")";
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000498 return;
499 }
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000500
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000501 _lastReceivedRrMs = _clock->TimeInMilliseconds();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000502 const RTCPPacketReportBlockItem& rb = rtcpPacket.ReportBlockItem;
503 reportBlock->remoteReceiveBlock.remoteSSRC = remoteSSRC;
504 reportBlock->remoteReceiveBlock.sourceSSRC = rb.SSRC;
505 reportBlock->remoteReceiveBlock.fractionLost = rb.FractionLost;
506 reportBlock->remoteReceiveBlock.cumulativeLost =
507 rb.CumulativeNumOfPacketsLost;
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000508 if (rb.ExtendedHighestSequenceNumber >
509 reportBlock->remoteReceiveBlock.extendedHighSeqNum) {
510 // We have successfully delivered new RTP packets to the remote side after
511 // the last RR was sent from the remote side.
512 _lastIncreasedSequenceNumberMs = _lastReceivedRrMs;
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000513 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000514 reportBlock->remoteReceiveBlock.extendedHighSeqNum =
515 rb.ExtendedHighestSequenceNumber;
516 reportBlock->remoteReceiveBlock.jitter = rb.Jitter;
517 reportBlock->remoteReceiveBlock.delaySinceLastSR = rb.DelayLastSR;
518 reportBlock->remoteReceiveBlock.lastSR = rb.LastSR;
519
520 if (rtcpPacket.ReportBlockItem.Jitter > reportBlock->remoteMaxJitter) {
521 reportBlock->remoteMaxJitter = rtcpPacket.ReportBlockItem.Jitter;
522 }
523
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100524 int64_t rtt = 0;
Danil Chapovalova094fd12016-02-22 18:59:36 +0100525 uint32_t send_time = rtcpPacket.ReportBlockItem.LastSR;
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100526 // RFC3550, section 6.4.1, LSR field discription states:
527 // If no SR has been received yet, the field is set to zero.
528 // Receiver rtp_rtcp module is not expected to calculate rtt using
529 // Sender Reports even if it accidentally can.
530 if (!receiver_only_ && send_time != 0) {
Danil Chapovalova094fd12016-02-22 18:59:36 +0100531 uint32_t delay = rtcpPacket.ReportBlockItem.DelayLastSR;
532 // Local NTP time.
533 uint32_t receive_time = CompactNtp(NtpTime(*_clock));
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000534
Danil Chapovalova094fd12016-02-22 18:59:36 +0100535 // RTT in 1/(2^16) seconds.
536 uint32_t rtt_ntp = receive_time - delay - send_time;
537 // Convert to 1/1000 seconds (milliseconds).
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100538 rtt = CompactNtpRttToMs(rtt_ntp);
Danil Chapovalova094fd12016-02-22 18:59:36 +0100539 if (rtt > reportBlock->maxRTT) {
540 // Store max RTT.
541 reportBlock->maxRTT = rtt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000543 if (reportBlock->minRTT == 0) {
Danil Chapovalova094fd12016-02-22 18:59:36 +0100544 // First RTT.
545 reportBlock->minRTT = rtt;
546 } else if (rtt < reportBlock->minRTT) {
547 // Store min RTT.
548 reportBlock->minRTT = rtt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000549 }
Danil Chapovalova094fd12016-02-22 18:59:36 +0100550 // Store last RTT.
551 reportBlock->RTT = rtt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000553 // store average RTT
554 if (reportBlock->numAverageCalcs != 0) {
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000555 float ac = static_cast<float>(reportBlock->numAverageCalcs);
556 float newAverage =
Danil Chapovalova094fd12016-02-22 18:59:36 +0100557 ((ac / (ac + 1)) * reportBlock->avgRTT) + ((1 / (ac + 1)) * rtt);
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000558 reportBlock->avgRTT = static_cast<int64_t>(newAverage + 0.5f);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000559 } else {
Danil Chapovalova094fd12016-02-22 18:59:36 +0100560 // First RTT.
561 reportBlock->avgRTT = rtt;
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000563 reportBlock->numAverageCalcs++;
564 }
565
sprang@webrtc.org0200f702015-02-16 12:06:00 +0000566 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RR_RTT", rb.SSRC,
Danil Chapovalova094fd12016-02-22 18:59:36 +0100567 rtt);
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +0000568
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000569 rtcpPacketInformation.AddReportInfo(*reportBlock);
niklase@google.com470e71d2011-07-07 08:21:25 +0000570}
571
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000572RTCPReportBlockInformation* RTCPReceiver::CreateOrGetReportBlockInformation(
573 uint32_t remote_ssrc,
574 uint32_t source_ssrc) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000575 RTCPReportBlockInformation* info =
576 GetReportBlockInformation(remote_ssrc, source_ssrc);
577 if (info == NULL) {
578 info = new RTCPReportBlockInformation;
579 _receivedReportBlockMap[source_ssrc][remote_ssrc] = info;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000580 }
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000581 return info;
niklase@google.com470e71d2011-07-07 08:21:25 +0000582}
583
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000584RTCPReportBlockInformation* RTCPReceiver::GetReportBlockInformation(
585 uint32_t remote_ssrc,
586 uint32_t source_ssrc) const {
587 ReportBlockMap::const_iterator it = _receivedReportBlockMap.find(source_ssrc);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000588 if (it == _receivedReportBlockMap.end()) {
589 return NULL;
590 }
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000591 const ReportBlockInfoMap* info_map = &(it->second);
592 ReportBlockInfoMap::const_iterator it_info = info_map->find(remote_ssrc);
593 if (it_info == info_map->end()) {
594 return NULL;
595 }
596 return it_info->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597}
598
danilchapda161d72016-08-19 07:29:46 -0700599RTCPCnameInformation* RTCPReceiver::CreateCnameInformation(
600 uint32_t remoteSSRC) {
danilchap7c9426c2016-04-14 03:05:31 -0700601 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000602
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000603 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000604 _receivedCnameMap.find(remoteSSRC);
605
606 if (it != _receivedCnameMap.end()) {
607 return it->second;
608 }
609 RTCPCnameInformation* cnameInfo = new RTCPCnameInformation;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000610 memset(cnameInfo->name, 0, RTCP_CNAME_SIZE);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000611 _receivedCnameMap[remoteSSRC] = cnameInfo;
612 return cnameInfo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000613}
614
danilchapda161d72016-08-19 07:29:46 -0700615RTCPCnameInformation* RTCPReceiver::GetCnameInformation(
616 uint32_t remoteSSRC) const {
danilchap7c9426c2016-04-14 03:05:31 -0700617 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000618
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000619 std::map<uint32_t, RTCPCnameInformation*>::const_iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000620 _receivedCnameMap.find(remoteSSRC);
621
622 if (it == _receivedCnameMap.end()) {
623 return NULL;
624 }
625 return it->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000626}
627
danilchapda161d72016-08-19 07:29:46 -0700628RTCPReceiveInformation* RTCPReceiver::CreateReceiveInformation(
629 uint32_t remoteSSRC) {
danilchap7c9426c2016-04-14 03:05:31 -0700630 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000631
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000632 std::map<uint32_t, RTCPReceiveInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000633 _receivedInfoMap.find(remoteSSRC);
634
635 if (it != _receivedInfoMap.end()) {
636 return it->second;
637 }
638 RTCPReceiveInformation* receiveInfo = new RTCPReceiveInformation;
639 _receivedInfoMap[remoteSSRC] = receiveInfo;
640 return receiveInfo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000641}
642
danilchapda161d72016-08-19 07:29:46 -0700643RTCPReceiveInformation* RTCPReceiver::GetReceiveInformation(
644 uint32_t remoteSSRC) {
danilchap7c9426c2016-04-14 03:05:31 -0700645 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000646
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000647 std::map<uint32_t, RTCPReceiveInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000648 _receivedInfoMap.find(remoteSSRC);
649 if (it == _receivedInfoMap.end()) {
650 return NULL;
651 }
652 return it->second;
niklase@google.com470e71d2011-07-07 08:21:25 +0000653}
654
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000655bool RTCPReceiver::RtcpRrTimeout(int64_t rtcp_interval_ms) {
danilchap7c9426c2016-04-14 03:05:31 -0700656 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000657 if (_lastReceivedRrMs == 0)
658 return false;
659
660 int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000661 if (_clock->TimeInMilliseconds() > _lastReceivedRrMs + time_out_ms) {
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000662 // Reset the timer to only trigger one log.
663 _lastReceivedRrMs = 0;
664 return true;
665 }
666 return false;
667}
668
669bool RTCPReceiver::RtcpRrSequenceNumberTimeout(int64_t rtcp_interval_ms) {
danilchap7c9426c2016-04-14 03:05:31 -0700670 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000671 if (_lastIncreasedSequenceNumberMs == 0)
672 return false;
673
674 int64_t time_out_ms = kRrTimeoutIntervals * rtcp_interval_ms;
danilchapda161d72016-08-19 07:29:46 -0700675 if (_clock->TimeInMilliseconds() >
676 _lastIncreasedSequenceNumberMs + time_out_ms) {
mflodman@webrtc.org2f225ca2013-01-09 13:54:43 +0000677 // Reset the timer to only trigger one log.
678 _lastIncreasedSequenceNumberMs = 0;
679 return true;
680 }
681 return false;
682}
683
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000684bool RTCPReceiver::UpdateRTCPReceiveInformationTimers() {
danilchap7c9426c2016-04-14 03:05:31 -0700685 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000686
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000687 bool updateBoundingSet = false;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000688 int64_t timeNow = _clock->TimeInMilliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000689
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000690 std::map<uint32_t, RTCPReceiveInformation*>::iterator receiveInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000691 _receivedInfoMap.begin();
niklase@google.com470e71d2011-07-07 08:21:25 +0000692
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000693 while (receiveInfoIt != _receivedInfoMap.end()) {
694 RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
695 if (receiveInfo == NULL) {
696 return updateBoundingSet;
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000698 // time since last received rtcp packet
699 // when we dont have a lastTimeReceived and the object is marked
700 // readyForDelete it's removed from the map
danilchap2b616392016-08-18 06:17:42 -0700701 if (receiveInfo->last_time_received_ms > 0) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000702 /// use audio define since we don't know what interval the remote peer is
703 // using
danilchap2b616392016-08-18 06:17:42 -0700704 if ((timeNow - receiveInfo->last_time_received_ms) >
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000705 5 * RTCP_INTERVAL_AUDIO_MS) {
706 // no rtcp packet for the last five regular intervals, reset limitations
danilchap2b616392016-08-18 06:17:42 -0700707 receiveInfo->ClearTmmbr();
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000708 // prevent that we call this over and over again
danilchap2b616392016-08-18 06:17:42 -0700709 receiveInfo->last_time_received_ms = 0;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000710 // send new TMMBN to all channels using the default codec
711 updateBoundingSet = true;
712 }
713 receiveInfoIt++;
danilchap2b616392016-08-18 06:17:42 -0700714 } else if (receiveInfo->ready_for_delete) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000715 // store our current receiveInfoItem
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000716 std::map<uint32_t, RTCPReceiveInformation*>::iterator
danilchapda161d72016-08-19 07:29:46 -0700717 receiveInfoItemToBeErased = receiveInfoIt;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000718 receiveInfoIt++;
719 delete receiveInfoItemToBeErased->second;
720 _receivedInfoMap.erase(receiveInfoItemToBeErased);
721 } else {
722 receiveInfoIt++;
723 }
724 }
725 return updateBoundingSet;
niklase@google.com470e71d2011-07-07 08:21:25 +0000726}
727
danilchap2b616392016-08-18 06:17:42 -0700728std::vector<rtcp::TmmbItem> RTCPReceiver::BoundingSet(bool* tmmbr_owner) {
danilchap7c9426c2016-04-14 03:05:31 -0700729 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000731 std::map<uint32_t, RTCPReceiveInformation*>::iterator receiveInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000732 _receivedInfoMap.find(_remoteSSRC);
733
734 if (receiveInfoIt == _receivedInfoMap.end()) {
danilchap2b616392016-08-18 06:17:42 -0700735 return std::vector<rtcp::TmmbItem>();
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000736 }
737 RTCPReceiveInformation* receiveInfo = receiveInfoIt->second;
danilchap2b616392016-08-18 06:17:42 -0700738 RTC_DCHECK(receiveInfo);
739
740 *tmmbr_owner = TMMBRHelp::IsOwner(receiveInfo->tmmbn, main_ssrc_);
741 return receiveInfo->tmmbn;
niklase@google.com470e71d2011-07-07 08:21:25 +0000742}
743
Erik Språnga38233a2015-07-24 09:58:18 +0200744void RTCPReceiver::HandleSDES(RTCPUtility::RTCPParserV2& rtcpParser,
745 RTCPPacketInformation& rtcpPacketInformation) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000746 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +0200747 while (pktType == RTCPPacketTypes::kSdesChunk) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000748 HandleSDESChunk(rtcpParser);
749 pktType = rtcpParser.Iterate();
750 }
Erik Språnga38233a2015-07-24 09:58:18 +0200751 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSdes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000752}
753
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000754void RTCPReceiver::HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser) {
755 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
756 RTCPCnameInformation* cnameInfo =
757 CreateCnameInformation(rtcpPacket.CName.SenderSSRC);
758 assert(cnameInfo);
niklase@google.com470e71d2011-07-07 08:21:25 +0000759
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000760 cnameInfo->name[RTCP_CNAME_SIZE - 1] = 0;
761 strncpy(cnameInfo->name, rtcpPacket.CName.CName, RTCP_CNAME_SIZE - 1);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000762 {
danilchap7c9426c2016-04-14 03:05:31 -0700763 rtc::CritScope lock(&_criticalSectionFeedbacks);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000764 if (stats_callback_ != NULL) {
765 stats_callback_->CNameChanged(rtcpPacket.CName.CName,
766 rtcpPacket.CName.SenderSSRC);
767 }
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000768 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000769}
770
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000771void RTCPReceiver::HandleNACK(RTCPUtility::RTCPParserV2& rtcpParser,
772 RTCPPacketInformation& rtcpPacketInformation) {
773 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
Peter Boströmfe7a80c2015-04-23 17:53:17 +0200774 if (receiver_only_ || main_ssrc_ != rtcpPacket.NACK.MediaSSRC) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000775 // Not to us.
776 rtcpParser.Iterate();
777 return;
778 }
779 rtcpPacketInformation.ResetNACKPacketIdArray();
niklase@google.com470e71d2011-07-07 08:21:25 +0000780
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000781 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +0200782 while (pktType == RTCPPacketTypes::kRtpfbNackItem) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000783 HandleNACKItem(rtcpPacket, rtcpPacketInformation);
784 pktType = rtcpParser.Iterate();
785 }
asapersson@webrtc.org8098e072014-02-19 11:59:02 +0000786
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000787 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
788 ++packet_type_counter_.nack_packets;
789 packet_type_counter_.nack_requests = nack_stats_.requests();
790 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
791 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000792}
793
danilchapda161d72016-08-19 07:29:46 -0700794void RTCPReceiver::HandleNACKItem(
795 const RTCPUtility::RTCPPacket& rtcpPacket,
796 RTCPPacketInformation& rtcpPacketInformation) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000797 rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID);
798 nack_stats_.ReportRequest(rtcpPacket.NACKItem.PacketID);
niklase@google.com470e71d2011-07-07 08:21:25 +0000799
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000800 uint16_t bitMask = rtcpPacket.NACKItem.BitMask;
801 if (bitMask) {
danilchapda161d72016-08-19 07:29:46 -0700802 for (int i = 1; i <= 16; ++i) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000803 if (bitMask & 0x01) {
804 rtcpPacketInformation.AddNACKPacket(rtcpPacket.NACKItem.PacketID + i);
805 nack_stats_.ReportRequest(rtcpPacket.NACKItem.PacketID + i);
806 }
danilchapda161d72016-08-19 07:29:46 -0700807 bitMask = bitMask >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000808 }
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000809 }
810 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpNack;
niklase@google.com470e71d2011-07-07 08:21:25 +0000811}
812
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000813void RTCPReceiver::HandleBYE(RTCPUtility::RTCPParserV2& rtcpParser) {
814 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000815
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000816 // clear our lists
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000817 ReportBlockMap::iterator it = _receivedReportBlockMap.begin();
818 for (; it != _receivedReportBlockMap.end(); ++it) {
819 ReportBlockInfoMap* info_map = &(it->second);
danilchapda161d72016-08-19 07:29:46 -0700820 ReportBlockInfoMap::iterator it_info =
821 info_map->find(rtcpPacket.BYE.SenderSSRC);
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000822 if (it_info != info_map->end()) {
823 delete it_info->second;
824 info_map->erase(it_info);
825 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000826 }
asapersson@webrtc.orgcb791412014-12-18 14:30:32 +0000827
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000828 // we can't delete it due to TMMBR
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000829 std::map<uint32_t, RTCPReceiveInformation*>::iterator receiveInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000830 _receivedInfoMap.find(rtcpPacket.BYE.SenderSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000831
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000832 if (receiveInfoIt != _receivedInfoMap.end()) {
danilchap2b616392016-08-18 06:17:42 -0700833 receiveInfoIt->second->ready_for_delete = true;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000834 }
835
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000836 std::map<uint32_t, RTCPCnameInformation*>::iterator cnameInfoIt =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000837 _receivedCnameMap.find(rtcpPacket.BYE.SenderSSRC);
838
839 if (cnameInfoIt != _receivedCnameMap.end()) {
840 delete cnameInfoIt->second;
841 _receivedCnameMap.erase(cnameInfoIt);
842 }
asapersson@webrtc.org7d6bd222013-10-31 12:14:34 +0000843 xr_rr_rtt_ms_ = 0;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000844 rtcpParser.Iterate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000845}
846
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000847void RTCPReceiver::HandleXrHeader(
848 RTCPUtility::RTCPParserV2& parser,
849 RTCPPacketInformation& rtcpPacketInformation) {
850 const RTCPUtility::RTCPPacket& packet = parser.Packet();
851
852 rtcpPacketInformation.xr_originator_ssrc = packet.XR.OriginatorSSRC;
853
854 parser.Iterate();
855}
856
857void RTCPReceiver::HandleXrReceiveReferenceTime(
858 RTCPUtility::RTCPParserV2& parser,
859 RTCPPacketInformation& rtcpPacketInformation) {
860 const RTCPUtility::RTCPPacket& packet = parser.Packet();
861
862 _remoteXRReceiveTimeInfo.sourceSSRC =
863 rtcpPacketInformation.xr_originator_ssrc;
864
865 _remoteXRReceiveTimeInfo.lastRR = RTCPUtility::MidNtp(
866 packet.XRReceiverReferenceTimeItem.NTPMostSignificant,
867 packet.XRReceiverReferenceTimeItem.NTPLeastSignificant);
868
869 _clock->CurrentNtp(_lastReceivedXRNTPsecs, _lastReceivedXRNTPfrac);
870
871 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
872
873 parser.Iterate();
874}
875
876void RTCPReceiver::HandleXrDlrrReportBlock(
877 RTCPUtility::RTCPParserV2& parser,
878 RTCPPacketInformation& rtcpPacketInformation) {
879 const RTCPUtility::RTCPPacket& packet = parser.Packet();
880 // Iterate through sub-block(s), if any.
881 RTCPUtility::RTCPPacketTypes packet_type = parser.Iterate();
882
Erik Språng242e22b2015-05-11 10:17:43 +0200883 while (packet_type == RTCPPacketTypes::kXrDlrrReportBlockItem) {
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000884 HandleXrDlrrReportBlockItem(packet, rtcpPacketInformation);
885 packet_type = parser.Iterate();
886 }
887}
888
889void RTCPReceiver::HandleXrDlrrReportBlockItem(
890 const RTCPUtility::RTCPPacket& packet,
andresp@webrtc.org7fb75ec2013-12-20 20:20:50 +0000891 RTCPPacketInformation& rtcpPacketInformation)
892 EXCLUSIVE_LOCKS_REQUIRED(_criticalSectionRTCPReceiver) {
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000893 if (registered_ssrcs_.find(packet.XRDLRRReportBlockItem.SSRC) ==
894 registered_ssrcs_.end()) {
895 // Not to us.
896 return;
897 }
898
899 rtcpPacketInformation.xr_dlrr_item = true;
900
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100901 // Caller should explicitly enable rtt calculation using extended reports.
902 if (!xr_rrtr_status_)
903 return;
904
Danil Chapovalova094fd12016-02-22 18:59:36 +0100905 // The send_time and delay_rr fields are in units of 1/2^16 sec.
906 uint32_t send_time = packet.XRDLRRReportBlockItem.LastRR;
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100907 // RFC3611, section 4.5, LRR field discription states:
Danil Chapovalova094fd12016-02-22 18:59:36 +0100908 // If no such block has been received, the field is set to zero.
909 if (send_time == 0)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000910 return;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000911
Danil Chapovalova094fd12016-02-22 18:59:36 +0100912 uint32_t delay_rr = packet.XRDLRRReportBlockItem.DelayLastRR;
913 uint32_t now = CompactNtp(NtpTime(*_clock));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000914
Danil Chapovalova094fd12016-02-22 18:59:36 +0100915 uint32_t rtt_ntp = now - delay_rr - send_time;
Danil Chapovalovc1e55c72016-03-09 15:14:35 +0100916 xr_rr_rtt_ms_ = CompactNtpRttToMs(rtt_ntp);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000917
918 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
919}
920
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +0000921void RTCPReceiver::HandlePLI(RTCPUtility::RTCPParserV2& rtcpParser,
922 RTCPPacketInformation& rtcpPacketInformation) {
923 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
stefan@webrtc.org28a331e2013-09-17 07:49:56 +0000924 if (main_ssrc_ == rtcpPacket.PLI.MediaSSRC) {
sprang@webrtc.org0200f702015-02-16 12:06:00 +0000925 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PLI");
justinlin@chromium.org7bfb3a32013-05-13 22:59:00 +0000926
asapersson@webrtc.org8098e072014-02-19 11:59:02 +0000927 ++packet_type_counter_.pli_packets;
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +0000928 // Received a signal that we need to send a new key frame.
929 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpPli;
930 }
931 rtcpParser.Iterate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000932}
933
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000934void RTCPReceiver::HandleTMMBR(RTCPUtility::RTCPParserV2& rtcpParser,
935 RTCPPacketInformation& rtcpPacketInformation) {
936 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000937
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000938 uint32_t senderSSRC = rtcpPacket.TMMBR.SenderSSRC;
939 RTCPReceiveInformation* ptrReceiveInfo = GetReceiveInformation(senderSSRC);
940 if (ptrReceiveInfo == NULL) {
941 // This remote SSRC must be saved before.
942 rtcpParser.Iterate();
943 return;
944 }
945 if (rtcpPacket.TMMBR.MediaSSRC) {
946 // rtcpPacket.TMMBR.MediaSSRC SHOULD be 0 if same as SenderSSRC
947 // in relay mode this is a valid number
948 senderSSRC = rtcpPacket.TMMBR.MediaSSRC;
949 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000950
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000951 // Use packet length to calc max number of TMMBR blocks
952 // each TMMBR block is 8 bytes
953 ptrdiff_t maxNumOfTMMBRBlocks = rtcpParser.LengthLeft() / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000954
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000955 // sanity, we can't have more than what's in one packet
956 if (maxNumOfTMMBRBlocks > 200) {
957 assert(false);
958 rtcpParser.Iterate();
959 return;
960 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000961
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000962 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +0200963 while (pktType == RTCPPacketTypes::kRtpfbTmmbrItem) {
danilchapda161d72016-08-19 07:29:46 -0700964 HandleTMMBRItem(*ptrReceiveInfo, rtcpPacket, rtcpPacketInformation,
965 senderSSRC);
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000966 pktType = rtcpParser.Iterate();
967 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000968}
969
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000970void RTCPReceiver::HandleTMMBRItem(RTCPReceiveInformation& receiveInfo,
971 const RTCPUtility::RTCPPacket& rtcpPacket,
972 RTCPPacketInformation& rtcpPacketInformation,
973 uint32_t senderSSRC) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000974 if (main_ssrc_ == rtcpPacket.TMMBRItem.SSRC &&
975 rtcpPacket.TMMBRItem.MaxTotalMediaBitRate > 0) {
danilchap2b616392016-08-18 06:17:42 -0700976 receiveInfo.InsertTmmbrItem(
977 senderSSRC,
978 rtcp::TmmbItem(rtcpPacket.TMMBRItem.SSRC,
979 rtcpPacket.TMMBRItem.MaxTotalMediaBitRate * 1000,
980 rtcpPacket.TMMBRItem.MeasuredOverhead),
981 _clock->TimeInMilliseconds());
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000982 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbr;
983 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000984}
985
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000986void RTCPReceiver::HandleTMMBN(RTCPUtility::RTCPParserV2& rtcpParser,
987 RTCPPacketInformation& rtcpPacketInformation) {
988 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
danilchapda161d72016-08-19 07:29:46 -0700989 RTCPReceiveInformation* ptrReceiveInfo =
990 GetReceiveInformation(rtcpPacket.TMMBN.SenderSSRC);
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000991 if (ptrReceiveInfo == NULL) {
992 // This remote SSRC must be saved before.
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 rtcpParser.Iterate();
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +0000994 return;
995 }
996 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpTmmbn;
997 // Use packet length to calc max number of TMMBN blocks
998 // each TMMBN block is 8 bytes
999 ptrdiff_t maxNumOfTMMBNBlocks = rtcpParser.LengthLeft() / 8;
1000
1001 // sanity, we cant have more than what's in one packet
1002 if (maxNumOfTMMBNBlocks > 200) {
1003 assert(false);
1004 rtcpParser.Iterate();
1005 return;
1006 }
1007
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001008 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +02001009 while (pktType == RTCPPacketTypes::kRtpfbTmmbnItem) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001010 HandleTMMBNItem(*ptrReceiveInfo, rtcpPacket);
1011 pktType = rtcpParser.Iterate();
1012 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001013}
1014
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001015void RTCPReceiver::HandleSR_REQ(RTCPUtility::RTCPParserV2& rtcpParser,
1016 RTCPPacketInformation& rtcpPacketInformation) {
1017 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpSrReq;
1018 rtcpParser.Iterate();
niklase@google.com470e71d2011-07-07 08:21:25 +00001019}
1020
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001021void RTCPReceiver::HandleTMMBNItem(RTCPReceiveInformation& receiveInfo,
1022 const RTCPUtility::RTCPPacket& rtcpPacket) {
danilchap2b616392016-08-18 06:17:42 -07001023 receiveInfo.tmmbn.emplace_back(
1024 rtcpPacket.TMMBNItem.SSRC,
1025 rtcpPacket.TMMBNItem.MaxTotalMediaBitRate * 1000,
1026 rtcpPacket.TMMBNItem.MeasuredOverhead);
niklase@google.com470e71d2011-07-07 08:21:25 +00001027}
1028
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001029void RTCPReceiver::HandleSLI(RTCPUtility::RTCPParserV2& rtcpParser,
1030 RTCPPacketInformation& rtcpPacketInformation) {
1031 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1032 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +02001033 while (pktType == RTCPPacketTypes::kPsfbSliItem) {
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001034 HandleSLIItem(rtcpPacket, rtcpPacketInformation);
1035 pktType = rtcpParser.Iterate();
1036 }
1037}
1038
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001039void RTCPReceiver::HandleSLIItem(const RTCPUtility::RTCPPacket& rtcpPacket,
1040 RTCPPacketInformation& rtcpPacketInformation) {
1041 // in theory there could be multiple slices lost
danilchapda161d72016-08-19 07:29:46 -07001042 rtcpPacketInformation.rtcpPacketTypeFlags |=
1043 kRtcpSli; // received signal that we need to refresh a slice
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001044 rtcpPacketInformation.sliPictureId = rtcpPacket.SLIItem.PictureId;
niklase@google.com470e71d2011-07-07 08:21:25 +00001045}
1046
danilchapda161d72016-08-19 07:29:46 -07001047void RTCPReceiver::HandleRPSI(
1048 RTCPUtility::RTCPParserV2& rtcpParser,
1049 RTCPHelp::RTCPPacketInformation& rtcpPacketInformation) {
1050 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1051 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
1052 if (pktType == RTCPPacketTypes::kPsfbRpsiItem) {
1053 if (rtcpPacket.RPSI.NumberOfValidBits % 8 != 0) {
1054 // to us unknown
1055 // continue
1056 rtcpParser.Iterate();
1057 return;
niklase@google.com470e71d2011-07-07 08:21:25 +00001058 }
danilchapda161d72016-08-19 07:29:46 -07001059 // Received signal that we have a confirmed reference picture.
1060 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRpsi;
1061 rtcpPacketInformation.rpsiPictureId = 0;
1062
1063 // convert NativeBitString to rpsiPictureId
1064 uint8_t numberOfBytes = rtcpPacket.RPSI.NumberOfValidBits / 8;
1065 for (uint8_t n = 0; n < (numberOfBytes - 1); n++) {
1066 rtcpPacketInformation.rpsiPictureId +=
1067 (rtcpPacket.RPSI.NativeBitString[n] & 0x7f);
1068 rtcpPacketInformation.rpsiPictureId <<= 7; // prepare next
1069 }
1070 rtcpPacketInformation.rpsiPictureId +=
1071 (rtcpPacket.RPSI.NativeBitString[numberOfBytes - 1] & 0x7f);
1072 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001073}
1074
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001075void RTCPReceiver::HandlePsfbApp(RTCPUtility::RTCPParserV2& rtcpParser,
1076 RTCPPacketInformation& rtcpPacketInformation) {
1077 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +02001078 if (pktType == RTCPPacketTypes::kPsfbRemb) {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001079 pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +02001080 if (pktType == RTCPPacketTypes::kPsfbRembItem) {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001081 HandleREMBItem(rtcpParser, rtcpPacketInformation);
1082 rtcpParser.Iterate();
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001083 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001084 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001085}
1086
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001087void RTCPReceiver::HandleREMBItem(
1088 RTCPUtility::RTCPParserV2& rtcpParser,
1089 RTCPPacketInformation& rtcpPacketInformation) {
1090 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1091 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpRemb;
1092 rtcpPacketInformation.receiverEstimatedMaxBitrate =
1093 rtcpPacket.REMBItem.BitRate;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001094}
1095
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001096void RTCPReceiver::HandleFIR(RTCPUtility::RTCPParserV2& rtcpParser,
1097 RTCPPacketInformation& rtcpPacketInformation) {
1098 const RTCPUtility::RTCPPacket& rtcpPacket = rtcpParser.Packet();
1099 RTCPReceiveInformation* ptrReceiveInfo =
1100 GetReceiveInformation(rtcpPacket.FIR.SenderSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001101
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001102 RTCPUtility::RTCPPacketTypes pktType = rtcpParser.Iterate();
Erik Språng242e22b2015-05-11 10:17:43 +02001103 while (pktType == RTCPPacketTypes::kPsfbFirItem) {
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001104 HandleFIRItem(ptrReceiveInfo, rtcpPacket, rtcpPacketInformation);
1105 pktType = rtcpParser.Iterate();
1106 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001107}
1108
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001109void RTCPReceiver::HandleFIRItem(RTCPReceiveInformation* receiveInfo,
1110 const RTCPUtility::RTCPPacket& rtcpPacket,
1111 RTCPPacketInformation& rtcpPacketInformation) {
1112 // Is it our sender that is requested to generate a new keyframe
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001113 if (main_ssrc_ != rtcpPacket.FIRItem.SSRC) {
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001114 return;
1115 }
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001116
1117 ++packet_type_counter_.fir_packets;
1118
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001119 // rtcpPacket.FIR.MediaSSRC SHOULD be 0 but we ignore to check it
1120 // we don't know who this originate from
1121 if (receiveInfo) {
1122 // check if we have reported this FIRSequenceNumber before
1123 if (rtcpPacket.FIRItem.CommandSequenceNumber !=
danilchap2b616392016-08-18 06:17:42 -07001124 receiveInfo->last_fir_sequence_number) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001125 int64_t now = _clock->TimeInMilliseconds();
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001126 // sanity; don't go crazy with the callbacks
danilchap2b616392016-08-18 06:17:42 -07001127 if ((now - receiveInfo->last_fir_request_ms) > RTCP_MIN_FRAME_LENGTH_MS) {
1128 receiveInfo->last_fir_request_ms = now;
1129 receiveInfo->last_fir_sequence_number =
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001130 rtcpPacket.FIRItem.CommandSequenceNumber;
1131 // received signal that we need to send a new key frame
1132 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir;
1133 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001134 }
pwestin@webrtc.orgb2179c22012-05-21 12:00:49 +00001135 } else {
1136 // received signal that we need to send a new key frame
1137 rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpFir;
1138 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001139}
1140
Erik Språng6b8d3552015-09-24 15:06:57 +02001141void RTCPReceiver::HandleTransportFeedback(
1142 RTCPUtility::RTCPParserV2* rtcp_parser,
1143 RTCPHelp::RTCPPacketInformation* rtcp_packet_information) {
1144 rtcp::RtcpPacket* packet = rtcp_parser->ReleaseRtcpPacket();
1145 RTC_DCHECK(packet != nullptr);
1146 rtcp_packet_information->rtcpPacketTypeFlags |= kRtcpTransportFeedback;
1147 rtcp_packet_information->transport_feedback_.reset(
1148 static_cast<rtcp::TransportFeedback*>(packet));
1149
1150 rtcp_parser->Iterate();
1151}
danilchap287e5482016-08-16 15:15:39 -07001152
danilchap853ecb22016-08-22 08:26:15 -07001153void RTCPReceiver::UpdateTmmbr() {
1154 // Find bounding set.
danilchap2f69ce92016-08-16 03:21:38 -07001155 std::vector<rtcp::TmmbItem> bounding =
danilchap853ecb22016-08-22 08:26:15 -07001156 TMMBRHelp::FindBoundingSet(TmmbrReceived());
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00001157
danilchap853ecb22016-08-22 08:26:15 -07001158 if (!bounding.empty() && _cbRtcpBandwidthObserver) {
1159 // We have a new bandwidth estimate on this channel.
danilchap2f69ce92016-08-16 03:21:38 -07001160 uint64_t bitrate_bps = TMMBRHelp::CalcMinBitrateBps(bounding);
1161 if (bitrate_bps <= std::numeric_limits<uint32_t>::max())
1162 _cbRtcpBandwidthObserver->OnReceivedEstimatedBitrate(bitrate_bps);
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00001163 }
danilchap853ecb22016-08-22 08:26:15 -07001164
1165 // Set bounding set: inform remote clients about the new bandwidth.
1166 _rtpRtcp.SetTmmbn(std::move(bounding));
niklase@google.com470e71d2011-07-07 08:21:25 +00001167}
1168
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001169void RTCPReceiver::RegisterRtcpStatisticsCallback(
1170 RtcpStatisticsCallback* callback) {
danilchap7c9426c2016-04-14 03:05:31 -07001171 rtc::CritScope cs(&_criticalSectionFeedbacks);
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001172 stats_callback_ = callback;
1173}
1174
1175RtcpStatisticsCallback* RTCPReceiver::GetRtcpStatisticsCallback() {
danilchap7c9426c2016-04-14 03:05:31 -07001176 rtc::CritScope cs(&_criticalSectionFeedbacks);
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001177 return stats_callback_;
1178}
1179
niklase@google.com470e71d2011-07-07 08:21:25 +00001180// Holding no Critical section
pwestin@webrtc.org3aa25de2012-01-05 08:40:56 +00001181void RTCPReceiver::TriggerCallbacksFromRTCPPacket(
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001182 RTCPPacketInformation& rtcpPacketInformation) {
1183 // Process TMMBR and REMB first to avoid multiple callbacks
1184 // to OnNetworkChanged.
1185 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr) {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001186 // Might trigger a OnReceivedBandwidthEstimateUpdate.
danilchap853ecb22016-08-22 08:26:15 -07001187 UpdateTmmbr();
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001188 }
sprang7dc39f32015-10-13 09:17:48 -07001189 uint32_t local_ssrc;
1190 std::set<uint32_t> registered_ssrcs;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001191 {
1192 // We don't want to hold this critsect when triggering the callbacks below.
danilchap7c9426c2016-04-14 03:05:31 -07001193 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
stefan@webrtc.org28a331e2013-09-17 07:49:56 +00001194 local_ssrc = main_ssrc_;
sprang7dc39f32015-10-13 09:17:48 -07001195 registered_ssrcs = registered_ssrcs_;
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001196 }
Peter Boströmfe7a80c2015-04-23 17:53:17 +02001197 if (!receiver_only_ &&
Erik Språng6b8d3552015-09-24 15:06:57 +02001198 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSrReq)) {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001199 _rtpRtcp.OnRequestSendReport();
1200 }
Peter Boströmfe7a80c2015-04-23 17:53:17 +02001201 if (!receiver_only_ &&
Erik Språng6b8d3552015-09-24 15:06:57 +02001202 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack)) {
stefan@webrtc.orgbecf9c82013-02-01 15:09:57 +00001203 if (rtcpPacketInformation.nackSequenceNumbers.size() > 0) {
andresp@webrtc.org4436b442014-06-04 09:05:30 +00001204 LOG(LS_VERBOSE) << "Incoming NACK length: "
danilchapda161d72016-08-19 07:29:46 -07001205 << rtcpPacketInformation.nackSequenceNumbers.size();
Danil Chapovalov2800d742016-08-26 18:48:46 +02001206 _rtpRtcp.OnReceivedNack(rtcpPacketInformation.nackSequenceNumbers);
pwestin@webrtc.org3aa25de2012-01-05 08:40:56 +00001207 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001208 }
1209 {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001210 // We need feedback that we have received a report block(s) so that we
1211 // can generate a new packet in a conference relay scenario, one received
1212 // report can generate several RTCP packets, based on number relayed/mixed
1213 // a send report block should go out to all receivers.
1214 if (_cbRtcpIntraFrameObserver) {
henrikg91d6ede2015-09-17 00:24:34 -07001215 RTC_DCHECK(!receiver_only_);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001216 if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) ||
1217 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpFir)) {
1218 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpPli) {
andresp@webrtc.org4436b442014-06-04 09:05:30 +00001219 LOG(LS_VERBOSE) << "Incoming PLI from SSRC "
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001220 << rtcpPacketInformation.remoteSSRC;
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001221 } else {
andresp@webrtc.org4436b442014-06-04 09:05:30 +00001222 LOG(LS_VERBOSE) << "Incoming FIR from SSRC "
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001223 << rtcpPacketInformation.remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00001224 }
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001225 _cbRtcpIntraFrameObserver->OnReceivedIntraFrameRequest(local_ssrc);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001226 }
1227 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSli) {
1228 _cbRtcpIntraFrameObserver->OnReceivedSLI(
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001229 local_ssrc, rtcpPacketInformation.sliPictureId);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001230 }
1231 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRpsi) {
1232 _cbRtcpIntraFrameObserver->OnReceivedRPSI(
mflodman@webrtc.orgaca26292012-10-05 16:17:41 +00001233 local_ssrc, rtcpPacketInformation.rpsiPictureId);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001234 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001235 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001236 if (_cbRtcpBandwidthObserver) {
henrikg91d6ede2015-09-17 00:24:34 -07001237 RTC_DCHECK(!receiver_only_);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001238 if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb) {
andresp@webrtc.org4436b442014-06-04 09:05:30 +00001239 LOG(LS_VERBOSE) << "Incoming REMB: "
asapersson@webrtc.orgdf7b65b2015-01-21 13:07:04 +00001240 << rtcpPacketInformation.receiverEstimatedMaxBitrate;
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001241 _cbRtcpBandwidthObserver->OnReceivedEstimatedBitrate(
1242 rtcpPacketInformation.receiverEstimatedMaxBitrate);
1243 }
Erik Språng242e22b2015-05-11 10:17:43 +02001244 if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr) ||
1245 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRr)) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001246 int64_t now = _clock->TimeInMilliseconds();
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001247 _cbRtcpBandwidthObserver->OnReceivedRtcpReceiverReport(
danilchapda161d72016-08-19 07:29:46 -07001248 rtcpPacketInformation.report_blocks, rtcpPacketInformation.rtt,
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001249 now);
1250 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001251 }
isheriff6b4b5f32016-06-08 00:24:21 -07001252 if ((rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSr) ||
1253 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRr)) {
1254 _rtpRtcp.OnReceivedRtcpReportBlocks(rtcpPacketInformation.report_blocks);
1255 }
1256
Erik Språng6b8d3552015-09-24 15:06:57 +02001257 if (_cbTransportFeedbackObserver &&
1258 (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTransportFeedback)) {
1259 uint32_t media_source_ssrc =
1260 rtcpPacketInformation.transport_feedback_->GetMediaSourceSsrc();
sprang7dc39f32015-10-13 09:17:48 -07001261 if (media_source_ssrc == local_ssrc ||
1262 registered_ssrcs.find(media_source_ssrc) != registered_ssrcs.end()) {
Erik Språng6b8d3552015-09-24 15:06:57 +02001263 _cbTransportFeedbackObserver->OnTransportFeedback(
1264 *rtcpPacketInformation.transport_feedback_.get());
1265 }
1266 }
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001267 }
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001268
Peter Boströmfe7a80c2015-04-23 17:53:17 +02001269 if (!receiver_only_) {
danilchap7c9426c2016-04-14 03:05:31 -07001270 rtc::CritScope cs(&_criticalSectionFeedbacks);
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001271 if (stats_callback_) {
1272 for (ReportBlockList::const_iterator it =
danilchapda161d72016-08-19 07:29:46 -07001273 rtcpPacketInformation.report_blocks.begin();
1274 it != rtcpPacketInformation.report_blocks.end(); ++it) {
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001275 RtcpStatistics stats;
1276 stats.cumulative_lost = it->cumulativeLost;
1277 stats.extended_max_sequence_number = it->extendedHighSeqNum;
1278 stats.fraction_lost = it->fractionLost;
1279 stats.jitter = it->jitter;
1280
stefan@webrtc.org58e2d262014-08-14 15:10:49 +00001281 stats_callback_->StatisticsUpdated(stats, it->sourceSSRC);
sprang@webrtc.orga6ad6e52013-12-05 09:48:44 +00001282 }
1283 }
1284 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001285}
1286
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001287int32_t RTCPReceiver::CNAME(uint32_t remoteSSRC,
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001288 char cName[RTCP_CNAME_SIZE]) const {
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001289 assert(cName);
1290
danilchap7c9426c2016-04-14 03:05:31 -07001291 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00001292 RTCPCnameInformation* cnameInfo = GetCnameInformation(remoteSSRC);
pwestin@webrtc.org49888ce2012-04-27 05:25:53 +00001293 if (cnameInfo == NULL) {
1294 return -1;
1295 }
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00001296 cName[RTCP_CNAME_SIZE - 1] = 0;
1297 strncpy(cName, cnameInfo->name, RTCP_CNAME_SIZE - 1);
1298 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001299}
1300
danilchap853ecb22016-08-22 08:26:15 -07001301std::vector<rtcp::TmmbItem> RTCPReceiver::TmmbrReceived() const {
danilchap7c9426c2016-04-14 03:05:31 -07001302 rtc::CritScope lock(&_criticalSectionRTCPReceiver);
danilchap287e5482016-08-16 15:15:39 -07001303 std::vector<rtcp::TmmbItem> candidates;
niklase@google.com470e71d2011-07-07 08:21:25 +00001304
danilchap287e5482016-08-16 15:15:39 -07001305 int64_t now_ms = _clock->TimeInMilliseconds();
1306
1307 for (const auto& kv : _receivedInfoMap) {
1308 RTCPReceiveInformation* receive_info = kv.second;
1309 RTC_DCHECK(receive_info);
danilchap2b616392016-08-18 06:17:42 -07001310 receive_info->GetTmmbrSet(now_ms, &candidates);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00001311 }
danilchap287e5482016-08-16 15:15:39 -07001312 return candidates;
niklase@google.com470e71d2011-07-07 08:21:25 +00001313}
1314
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001315} // namespace webrtc