blob: e3cb16d17e1bad95f26040ce2ed32b686e020e5d [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_sender.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h> // assert
stefan@webrtc.org9354cc92012-06-07 08:10:14 +000014#include <string.h> // memcpy
niklase@google.com470e71d2011-07-07 08:21:25 +000015
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000016#include <algorithm> // min
Erik Språng61be2a42015-04-27 13:32:52 +020017#include <limits> // max
danilchapb8b6fbb2015-12-10 05:05:27 -080018#include <utility>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000019
Erik Språng61be2a42015-04-27 13:32:52 +020020#include "webrtc/base/checks.h"
Peter Boströmebc0b4e2015-10-28 16:39:33 +010021#include "webrtc/base/logging.h"
tommie4f96502015-10-20 23:00:48 -070022#include "webrtc/base/trace_event.h"
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000023#include "webrtc/common_types.h"
sprang@webrtc.org779c3d12015-03-17 16:42:49 +000024#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
danilchap0219c9b2015-11-18 05:56:53 -080025#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h"
danilchap50c51362015-11-22 09:03:11 -080026#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
danilchapa8890a52015-12-22 03:43:04 -080027#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h"
danilchapf8385ad2015-11-27 05:36:09 -080028#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h"
Danil Chapovalov97f7e132015-12-04 16:13:30 +010029#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
danilchapef3d8052016-01-11 03:31:08 -080030#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
sprang233bd872015-09-08 13:25:16 -070031#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
tommie4f96502015-10-20 23:00:48 -070032#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010033#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
pwestin@webrtc.org741da942011-09-20 13:52:04 +000034
niklase@google.com470e71d2011-07-07 08:21:25 +000035namespace webrtc {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000036
37using RTCPUtility::RTCPCnameInformation;
38
Erik Språng61be2a42015-04-27 13:32:52 +020039NACKStringBuilder::NACKStringBuilder()
danilchap162abd32015-12-10 02:39:40 -080040 : stream_(""), count_(0), prevNack_(0), consecutive_(false) {}
edjee@google.com79b02892013-04-04 19:43:34 +000041
pbos@webrtc.orgf3e4cee2013-07-31 15:17:19 +000042NACKStringBuilder::~NACKStringBuilder() {}
43
danilchap162abd32015-12-10 02:39:40 -080044void NACKStringBuilder::PushNACK(uint16_t nack) {
Erik Språng242e22b2015-05-11 10:17:43 +020045 if (count_ == 0) {
46 stream_ << nack;
47 } else if (nack == prevNack_ + 1) {
48 consecutive_ = true;
Erik Språng61be2a42015-04-27 13:32:52 +020049 } else {
Erik Språng242e22b2015-05-11 10:17:43 +020050 if (consecutive_) {
51 stream_ << "-" << prevNack_;
52 consecutive_ = false;
edjee@google.com79b02892013-04-04 19:43:34 +000053 }
Erik Språng242e22b2015-05-11 10:17:43 +020054 stream_ << "," << nack;
Erik Språng61be2a42015-04-27 13:32:52 +020055 }
Erik Språng242e22b2015-05-11 10:17:43 +020056 count_++;
57 prevNack_ = nack;
edjee@google.com79b02892013-04-04 19:43:34 +000058}
59
Erik Språng61be2a42015-04-27 13:32:52 +020060std::string NACKStringBuilder::GetResult() {
Erik Språng242e22b2015-05-11 10:17:43 +020061 if (consecutive_) {
62 stream_ << "-" << prevNack_;
63 consecutive_ = false;
Erik Språng61be2a42015-04-27 13:32:52 +020064 }
Erik Språng242e22b2015-05-11 10:17:43 +020065 return stream_.str();
edjee@google.com79b02892013-04-04 19:43:34 +000066}
67
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000068RTCPSender::FeedbackState::FeedbackState()
69 : send_payload_type(0),
70 frequency_hz(0),
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +000071 packets_sent(0),
72 media_bytes_sent(0),
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000073 send_bitrate(0),
74 last_rr_ntp_secs(0),
75 last_rr_ntp_frac(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000076 remote_sr(0),
Erik Språng61be2a42015-04-27 13:32:52 +020077 has_last_xr_rr(false),
danilchap162abd32015-12-10 02:39:40 -080078 module(nullptr) {}
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000079
Erik Språngf7c57762015-12-04 10:40:35 +010080class PacketContainer : public rtcp::Empty,
81 public rtcp::RtcpPacket::PacketReadyCallback {
82 public:
83 explicit PacketContainer(Transport* transport)
84 : transport_(transport), bytes_sent_(0) {}
85 virtual ~PacketContainer() {
86 for (RtcpPacket* packet : appended_packets_)
87 delete packet;
88 }
89
90 void OnPacketReady(uint8_t* data, size_t length) override {
91 if (transport_->SendRtcp(data, length))
92 bytes_sent_ += length;
93 }
94
95 size_t SendPackets() {
96 rtcp::Empty::Build(this);
97 return bytes_sent_;
98 }
99
100 private:
101 Transport* transport_;
102 size_t bytes_sent_;
103};
104
105class RTCPSender::RtcpContext {
106 public:
Erik Språng242e22b2015-05-11 10:17:43 +0200107 RtcpContext(const FeedbackState& feedback_state,
108 int32_t nack_size,
109 const uint16_t* nack_list,
110 bool repeat,
111 uint64_t picture_id,
Erik Språngf7c57762015-12-04 10:40:35 +0100112 uint32_t ntp_sec,
113 uint32_t ntp_frac,
114 PacketContainer* container)
115 : feedback_state_(feedback_state),
116 nack_size_(nack_size),
117 nack_list_(nack_list),
118 repeat_(repeat),
119 picture_id_(picture_id),
120 ntp_sec_(ntp_sec),
121 ntp_frac_(ntp_frac),
122 container_(container) {}
Erik Språng242e22b2015-05-11 10:17:43 +0200123
Erik Språngf7c57762015-12-04 10:40:35 +0100124 virtual ~RtcpContext() {}
Erik Språng242e22b2015-05-11 10:17:43 +0200125
Erik Språngf7c57762015-12-04 10:40:35 +0100126 const FeedbackState& feedback_state_;
127 const int32_t nack_size_;
128 const uint16_t* nack_list_;
129 const bool repeat_;
130 const uint64_t picture_id_;
131 const uint32_t ntp_sec_;
132 const uint32_t ntp_frac_;
Erik Språng242e22b2015-05-11 10:17:43 +0200133
Erik Språngf7c57762015-12-04 10:40:35 +0100134 PacketContainer* const container_;
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200135};
136
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000137RTCPSender::RTCPSender(
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000138 bool audio,
139 Clock* clock,
140 ReceiveStatistics* receive_statistics,
sprang86fd9ed2015-09-29 04:45:43 -0700141 RtcpPacketTypeCounterObserver* packet_type_counter_observer,
142 Transport* outgoing_transport)
Peter Boströmac547a62015-09-17 23:03:57 +0200143 : audio_(audio),
Erik Språng242e22b2015-05-11 10:17:43 +0200144 clock_(clock),
danilchap47a740b2015-12-15 00:30:07 -0800145 random_(clock_->TimeInMicroseconds()),
pbosda903ea2015-10-02 02:36:56 -0700146 method_(RtcpMode::kOff),
sprang86fd9ed2015-09-29 04:45:43 -0700147 transport_(outgoing_transport),
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
Erik Språng242e22b2015-05-11 10:17:43 +0200149 critical_section_rtcp_sender_(
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000150 CriticalSectionWrapper::CreateCriticalSection()),
Erik Språng242e22b2015-05-11 10:17:43 +0200151 using_nack_(false),
152 sending_(false),
153 remb_enabled_(false),
Erik Språng242e22b2015-05-11 10:17:43 +0200154 next_time_to_send_rtcp_(0),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000155 start_timestamp_(0),
156 last_rtp_timestamp_(0),
157 last_frame_capture_time_ms_(-1),
Erik Språng242e22b2015-05-11 10:17:43 +0200158 ssrc_(0),
159 remote_ssrc_(0),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000160 receive_statistics_(receive_statistics),
niklase@google.com470e71d2011-07-07 08:21:25 +0000161
Erik Språng242e22b2015-05-11 10:17:43 +0200162 sequence_number_fir_(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000163
Erik Språng242e22b2015-05-11 10:17:43 +0200164 remb_bitrate_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000165
Erik Språng242e22b2015-05-11 10:17:43 +0200166 tmmbr_help_(),
167 tmmbr_send_(0),
168 packet_oh_send_(0),
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000169
Erik Språng242e22b2015-05-11 10:17:43 +0200170 app_sub_type_(0),
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200171 app_name_(0),
Erik Språng242e22b2015-05-11 10:17:43 +0200172 app_data_(nullptr),
173 app_length_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
Erik Språng242e22b2015-05-11 10:17:43 +0200175 xr_send_receiver_reference_time_enabled_(false),
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000176 packet_type_counter_observer_(packet_type_counter_observer) {
Erik Språng242e22b2015-05-11 10:17:43 +0200177 memset(last_send_report_, 0, sizeof(last_send_report_));
178 memset(last_rtcp_time_, 0, sizeof(last_rtcp_time_));
sprang86fd9ed2015-09-29 04:45:43 -0700179 RTC_DCHECK(transport_ != nullptr);
Erik Språng242e22b2015-05-11 10:17:43 +0200180
181 builders_[kRtcpSr] = &RTCPSender::BuildSR;
182 builders_[kRtcpRr] = &RTCPSender::BuildRR;
Erik Språng0ea42d32015-06-25 14:46:16 +0200183 builders_[kRtcpSdes] = &RTCPSender::BuildSDES;
Erik Språng242e22b2015-05-11 10:17:43 +0200184 builders_[kRtcpPli] = &RTCPSender::BuildPLI;
185 builders_[kRtcpFir] = &RTCPSender::BuildFIR;
186 builders_[kRtcpSli] = &RTCPSender::BuildSLI;
187 builders_[kRtcpRpsi] = &RTCPSender::BuildRPSI;
188 builders_[kRtcpRemb] = &RTCPSender::BuildREMB;
189 builders_[kRtcpBye] = &RTCPSender::BuildBYE;
190 builders_[kRtcpApp] = &RTCPSender::BuildAPP;
191 builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
192 builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
193 builders_[kRtcpNack] = &RTCPSender::BuildNACK;
194 builders_[kRtcpXrVoipMetric] = &RTCPSender::BuildVoIPMetric;
195 builders_[kRtcpXrReceiverReferenceTime] =
196 &RTCPSender::BuildReceiverReferenceTime;
197 builders_[kRtcpXrDlrrReportBlock] = &RTCPSender::BuildDlrr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000198}
199
danilchap162abd32015-12-10 02:39:40 -0800200RTCPSender::~RTCPSender() {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
pbosda903ea2015-10-02 02:36:56 -0700202RtcpMode RTCPSender::Status() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200203 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
204 return method_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
206
pbosda903ea2015-10-02 02:36:56 -0700207void RTCPSender::SetRTCPStatus(RtcpMode method) {
Erik Språng242e22b2015-05-11 10:17:43 +0200208 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
209 method_ = method;
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000210
pbosda903ea2015-10-02 02:36:56 -0700211 if (method == RtcpMode::kOff)
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000212 return;
Erik Språng242e22b2015-05-11 10:17:43 +0200213 next_time_to_send_rtcp_ =
214 clock_->TimeInMilliseconds() +
215 (audio_ ? RTCP_INTERVAL_AUDIO_MS / 2 : RTCP_INTERVAL_VIDEO_MS / 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000216}
217
Erik Språng61be2a42015-04-27 13:32:52 +0200218bool RTCPSender::Sending() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200219 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
220 return sending_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000221}
222
Erik Språng61be2a42015-04-27 13:32:52 +0200223int32_t RTCPSender::SetSendingStatus(const FeedbackState& feedback_state,
224 bool sending) {
225 bool sendRTCPBye = false;
226 {
Erik Språng242e22b2015-05-11 10:17:43 +0200227 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
pbosda903ea2015-10-02 02:36:56 -0700229 if (method_ != RtcpMode::kOff) {
Erik Språng242e22b2015-05-11 10:17:43 +0200230 if (sending == false && sending_ == true) {
Erik Språng61be2a42015-04-27 13:32:52 +0200231 // Trigger RTCP bye
232 sendRTCPBye = true;
233 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 }
Erik Språng242e22b2015-05-11 10:17:43 +0200235 sending_ = sending;
Erik Språng61be2a42015-04-27 13:32:52 +0200236 }
237 if (sendRTCPBye)
238 return SendRTCP(feedback_state, kRtcpBye);
239 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000240}
241
Erik Språng61be2a42015-04-27 13:32:52 +0200242bool RTCPSender::REMB() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200243 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
244 return remb_enabled_;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000245}
246
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000247void RTCPSender::SetREMBStatus(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200248 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
249 remb_enabled_ = enable;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000250}
251
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000252void RTCPSender::SetREMBData(uint32_t bitrate,
253 const std::vector<uint32_t>& ssrcs) {
Erik Språng242e22b2015-05-11 10:17:43 +0200254 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
255 remb_bitrate_ = bitrate;
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000256 remb_ssrcs_ = ssrcs;
stefan@webrtc.org4ef438e2014-07-11 09:55:30 +0000257
Erik Språng242e22b2015-05-11 10:17:43 +0200258 if (remb_enabled_)
259 SetFlag(kRtcpRemb, false);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000260 // Send a REMB immediately if we have a new REMB. The frequency of REMBs is
261 // throttled by the caller.
Erik Språng242e22b2015-05-11 10:17:43 +0200262 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds();
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000263}
264
Erik Språng61be2a42015-04-27 13:32:52 +0200265bool RTCPSender::TMMBR() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200266 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
267 return IsFlagPresent(RTCPPacketType::kRtcpTmmbr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000268}
269
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000270void RTCPSender::SetTMMBRStatus(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200271 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
272 if (enable) {
273 SetFlag(RTCPPacketType::kRtcpTmmbr, false);
274 } else {
275 ConsumeFlag(RTCPPacketType::kRtcpTmmbr, true);
276 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000277}
278
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000279void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
Erik Språng242e22b2015-05-11 10:17:43 +0200280 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000281 start_timestamp_ = start_timestamp;
282}
283
284void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
285 int64_t capture_time_ms) {
Erik Språng242e22b2015-05-11 10:17:43 +0200286 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000287 last_rtp_timestamp_ = rtp_timestamp;
288 if (capture_time_ms < 0) {
289 // We don't currently get a capture time from VoiceEngine.
Erik Språng242e22b2015-05-11 10:17:43 +0200290 last_frame_capture_time_ms_ = clock_->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000291 } else {
292 last_frame_capture_time_ms_ = capture_time_ms;
293 }
294}
295
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000296void RTCPSender::SetSSRC(uint32_t ssrc) {
Erik Språng242e22b2015-05-11 10:17:43 +0200297 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
Erik Språng242e22b2015-05-11 10:17:43 +0200299 if (ssrc_ != 0) {
Erik Språng61be2a42015-04-27 13:32:52 +0200300 // not first SetSSRC, probably due to a collision
301 // schedule a new RTCP report
302 // make sure that we send a RTP packet
Erik Språng242e22b2015-05-11 10:17:43 +0200303 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + 100;
Erik Språng61be2a42015-04-27 13:32:52 +0200304 }
Erik Språng242e22b2015-05-11 10:17:43 +0200305 ssrc_ = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000306}
307
Erik Språng61be2a42015-04-27 13:32:52 +0200308void RTCPSender::SetRemoteSSRC(uint32_t ssrc) {
Erik Språng242e22b2015-05-11 10:17:43 +0200309 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
310 remote_ssrc_ = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000311}
312
Peter Boström9ba52f82015-06-01 14:12:28 +0200313int32_t RTCPSender::SetCNAME(const char* c_name) {
314 if (!c_name)
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000315 return -1;
316
henrikg91d6ede2015-09-17 00:24:34 -0700317 RTC_DCHECK_LT(strlen(c_name), static_cast<size_t>(RTCP_CNAME_SIZE));
Erik Språng242e22b2015-05-11 10:17:43 +0200318 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200319 cname_ = c_name;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000320 return 0;
321}
322
Erik Språng0ea42d32015-06-25 14:46:16 +0200323int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC, const char* c_name) {
324 assert(c_name);
henrikg91d6ede2015-09-17 00:24:34 -0700325 RTC_DCHECK_LT(strlen(c_name), static_cast<size_t>(RTCP_CNAME_SIZE));
Erik Språng242e22b2015-05-11 10:17:43 +0200326 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200327 if (csrc_cnames_.size() >= kRtpCsrcSize)
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000328 return -1;
Erik Språng0ea42d32015-06-25 14:46:16 +0200329
330 csrc_cnames_[SSRC] = c_name;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000331 return 0;
332}
333
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000334int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
Erik Språng242e22b2015-05-11 10:17:43 +0200335 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200336 auto it = csrc_cnames_.find(SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000337
Erik Språng242e22b2015-05-11 10:17:43 +0200338 if (it == csrc_cnames_.end())
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000339 return -1;
Erik Språng61be2a42015-04-27 13:32:52 +0200340
Erik Språng242e22b2015-05-11 10:17:43 +0200341 csrc_cnames_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000342 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000343}
344
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000345bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
danilchap162abd32015-12-10 02:39:40 -0800346 /*
347 For audio we use a fix 5 sec interval
niklase@google.com470e71d2011-07-07 08:21:25 +0000348
danilchap162abd32015-12-10 02:39:40 -0800349 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
350 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but
351 that should be extremely rare
niklase@google.com470e71d2011-07-07 08:21:25 +0000352
353
danilchap162abd32015-12-10 02:39:40 -0800354 From RFC 3550
niklase@google.com470e71d2011-07-07 08:21:25 +0000355
danilchap162abd32015-12-10 02:39:40 -0800356 MAX RTCP BW is 5% if the session BW
357 A send report is approximately 65 bytes inc CNAME
358 A receiver report is approximately 28 bytes
niklase@google.com470e71d2011-07-07 08:21:25 +0000359
danilchap162abd32015-12-10 02:39:40 -0800360 The RECOMMENDED value for the reduced minimum in seconds is 360
361 divided by the session bandwidth in kilobits/second. This minimum
362 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
niklase@google.com470e71d2011-07-07 08:21:25 +0000363
danilchap162abd32015-12-10 02:39:40 -0800364 If the participant has not yet sent an RTCP packet (the variable
365 initial is true), the constant Tmin is set to 2.5 seconds, else it
366 is set to 5 seconds.
niklase@google.com470e71d2011-07-07 08:21:25 +0000367
danilchap162abd32015-12-10 02:39:40 -0800368 The interval between RTCP packets is varied randomly over the
369 range [0.5,1.5] times the calculated interval to avoid unintended
370 synchronization of all participants
niklase@google.com470e71d2011-07-07 08:21:25 +0000371
danilchap162abd32015-12-10 02:39:40 -0800372 if we send
373 If the participant is a sender (we_sent true), the constant C is
374 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
375 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
376 number of senders.
niklase@google.com470e71d2011-07-07 08:21:25 +0000377
danilchap162abd32015-12-10 02:39:40 -0800378 if we receive only
379 If we_sent is not true, the constant C is set
380 to the average RTCP packet size divided by 75% of the RTCP
381 bandwidth. The constant n is set to the number of receivers
382 (members - senders). If the number of senders is greater than
383 25%, senders and receivers are treated together.
niklase@google.com470e71d2011-07-07 08:21:25 +0000384
danilchap162abd32015-12-10 02:39:40 -0800385 reconsideration NOT required for peer-to-peer
386 "timer reconsideration" is
387 employed. This algorithm implements a simple back-off mechanism
388 which causes users to hold back RTCP packet transmission if the
389 group sizes are increasing.
niklase@google.com470e71d2011-07-07 08:21:25 +0000390
danilchap162abd32015-12-10 02:39:40 -0800391 n = number of members
392 C = avg_size/(rtcpBW/4)
niklase@google.com470e71d2011-07-07 08:21:25 +0000393
danilchap162abd32015-12-10 02:39:40 -0800394 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
niklase@google.com470e71d2011-07-07 08:21:25 +0000395
danilchap162abd32015-12-10 02:39:40 -0800396 4. The calculated interval T is set to a number uniformly distributed
397 between 0.5 and 1.5 times the deterministic calculated interval.
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
danilchap162abd32015-12-10 02:39:40 -0800399 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
400 for the fact that the timer reconsideration algorithm converges to
401 a value of the RTCP bandwidth below the intended average
402 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000403
Erik Språng242e22b2015-05-11 10:17:43 +0200404 int64_t now = clock_->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000405
Erik Språng242e22b2015-05-11 10:17:43 +0200406 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
xians@webrtc.org8738d272011-11-25 13:43:53 +0000407
pbosda903ea2015-10-02 02:36:56 -0700408 if (method_ == RtcpMode::kOff)
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000410
Erik Språng242e22b2015-05-11 10:17:43 +0200411 if (!audio_ && sendKeyframeBeforeRTP) {
Erik Språng61be2a42015-04-27 13:32:52 +0200412 // for video key-frames we want to send the RTCP before the large key-frame
413 // if we have a 100 ms margin
414 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
415 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000416
Erik Språng242e22b2015-05-11 10:17:43 +0200417 if (now >= next_time_to_send_rtcp_) {
Erik Språng61be2a42015-04-27 13:32:52 +0200418 return true;
419 } else if (now < 0x0000ffff &&
Erik Språng242e22b2015-05-11 10:17:43 +0200420 next_time_to_send_rtcp_ > 0xffff0000) { // 65 sec margin
Erik Språng61be2a42015-04-27 13:32:52 +0200421 // wrap
422 return true;
423 }
424 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000425}
426
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000427int64_t RTCPSender::SendTimeOfSendReport(uint32_t sendReport) {
Erik Språng242e22b2015-05-11 10:17:43 +0200428 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000429
Erik Språng61be2a42015-04-27 13:32:52 +0200430 // This is only saved when we are the sender
Erik Språng242e22b2015-05-11 10:17:43 +0200431 if ((last_send_report_[0] == 0) || (sendReport == 0)) {
Erik Språng61be2a42015-04-27 13:32:52 +0200432 return 0; // will be ignored
433 } else {
434 for (int i = 0; i < RTCP_NUMBER_OF_SR; ++i) {
Erik Språng242e22b2015-05-11 10:17:43 +0200435 if (last_send_report_[i] == sendReport)
436 return last_rtcp_time_[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000437 }
Erik Språng61be2a42015-04-27 13:32:52 +0200438 }
439 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000440}
441
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000442bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
443 int64_t* time_ms) const {
Erik Språng242e22b2015-05-11 10:17:43 +0200444 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000445
446 if (last_xr_rr_.empty()) {
447 return false;
448 }
449 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
450 if (it == last_xr_rr_.end()) {
451 return false;
452 }
453 *time_ms = it->second;
454 return true;
455}
456
Erik Språngf7c57762015-12-04 10:40:35 +0100457rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSR(const RtcpContext& ctx) {
Erik Språng61be2a42015-04-27 13:32:52 +0200458 for (int i = (RTCP_NUMBER_OF_SR - 2); i >= 0; i--) {
459 // shift old
Erik Språng242e22b2015-05-11 10:17:43 +0200460 last_send_report_[i + 1] = last_send_report_[i];
461 last_rtcp_time_[i + 1] = last_rtcp_time_[i];
Erik Språng61be2a42015-04-27 13:32:52 +0200462 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
Erik Språngf7c57762015-12-04 10:40:35 +0100464 last_rtcp_time_[0] = Clock::NtpToMs(ctx.ntp_sec_, ctx.ntp_frac_);
465 last_send_report_[0] = (ctx.ntp_sec_ << 16) + (ctx.ntp_frac_ >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000466
Erik Språng61be2a42015-04-27 13:32:52 +0200467 // The timestamp of this RTCP packet should be estimated as the timestamp of
468 // the frame being captured at this moment. We are calculating that
469 // timestamp as the last frame's timestamp + the time since the last frame
470 // was captured.
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200471 uint32_t rtp_timestamp =
472 start_timestamp_ + last_rtp_timestamp_ +
473 (clock_->TimeInMilliseconds() - last_frame_capture_time_ms_) *
Erik Språngf7c57762015-12-04 10:40:35 +0100474 (ctx.feedback_state_.frequency_hz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000475
Erik Språngf7c57762015-12-04 10:40:35 +0100476 rtcp::SenderReport* report = new rtcp::SenderReport();
477 report->From(ssrc_);
478 report->WithNtpSec(ctx.ntp_sec_);
479 report->WithNtpFrac(ctx.ntp_frac_);
480 report->WithRtpTimestamp(rtp_timestamp);
481 report->WithPacketCount(ctx.feedback_state_.packets_sent);
482 report->WithOctetCount(ctx.feedback_state_.media_bytes_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000483
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200484 for (auto it : report_blocks_)
Erik Språngf7c57762015-12-04 10:40:35 +0100485 report->WithReportBlock(it.second);
niklase@google.com470e71d2011-07-07 08:21:25 +0000486
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200487 report_blocks_.clear();
Erik Språngf7c57762015-12-04 10:40:35 +0100488
489 return rtc::scoped_ptr<rtcp::SenderReport>(report);
niklase@google.com470e71d2011-07-07 08:21:25 +0000490}
491
Erik Språngf7c57762015-12-04 10:40:35 +0100492rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSDES(
493 const RtcpContext& ctx) {
Erik Språng0ea42d32015-06-25 14:46:16 +0200494 size_t length_cname = cname_.length();
henrikg91d6ede2015-09-17 00:24:34 -0700495 RTC_CHECK_LT(length_cname, static_cast<size_t>(RTCP_CNAME_SIZE));
niklase@google.com470e71d2011-07-07 08:21:25 +0000496
Erik Språngf7c57762015-12-04 10:40:35 +0100497 rtcp::Sdes* sdes = new rtcp::Sdes();
498 sdes->WithCName(ssrc_, cname_);
Erik Språng0ea42d32015-06-25 14:46:16 +0200499
500 for (const auto it : csrc_cnames_)
Erik Språngf7c57762015-12-04 10:40:35 +0100501 sdes->WithCName(it.first, it.second);
Erik Språng0ea42d32015-06-25 14:46:16 +0200502
Erik Språngf7c57762015-12-04 10:40:35 +0100503 return rtc::scoped_ptr<rtcp::Sdes>(sdes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000504}
505
Erik Språngf7c57762015-12-04 10:40:35 +0100506rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildRR(const RtcpContext& ctx) {
507 rtcp::ReceiverReport* report = new rtcp::ReceiverReport();
508 report->From(ssrc_);
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200509 for (auto it : report_blocks_)
Erik Språngf7c57762015-12-04 10:40:35 +0100510 report->WithReportBlock(it.second);
Erik Språng61be2a42015-04-27 13:32:52 +0200511
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200512 report_blocks_.clear();
Erik Språngf7c57762015-12-04 10:40:35 +0100513 return rtc::scoped_ptr<rtcp::ReceiverReport>(report);
niklase@google.com470e71d2011-07-07 08:21:25 +0000514}
515
Erik Språngf7c57762015-12-04 10:40:35 +0100516rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildPLI(const RtcpContext& ctx) {
517 rtcp::Pli* pli = new rtcp::Pli();
518 pli->From(ssrc_);
519 pli->To(remote_ssrc_);
Erik Språng61be2a42015-04-27 13:32:52 +0200520
Erik Språng242e22b2015-05-11 10:17:43 +0200521 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
522 "RTCPSender::PLI");
523 ++packet_type_counter_.pli_packets;
524 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_PLICount",
525 ssrc_, packet_type_counter_.pli_packets);
526
Erik Språngf7c57762015-12-04 10:40:35 +0100527 return rtc::scoped_ptr<rtcp::Pli>(pli);
Erik Språng61be2a42015-04-27 13:32:52 +0200528}
529
Erik Språngf7c57762015-12-04 10:40:35 +0100530rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildFIR(const RtcpContext& ctx) {
531 if (!ctx.repeat_)
sprang62dae192015-08-05 02:35:35 -0700532 ++sequence_number_fir_; // Do not increase if repetition.
niklase@google.com470e71d2011-07-07 08:21:25 +0000533
Erik Språngf7c57762015-12-04 10:40:35 +0100534 rtcp::Fir* fir = new rtcp::Fir();
535 fir->From(ssrc_);
536 fir->To(remote_ssrc_);
537 fir->WithCommandSeqNum(sequence_number_fir_);
Erik Språng242e22b2015-05-11 10:17:43 +0200538
539 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
540 "RTCPSender::FIR");
541 ++packet_type_counter_.fir_packets;
542 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_FIRCount",
543 ssrc_, packet_type_counter_.fir_packets);
544
Erik Språngf7c57762015-12-04 10:40:35 +0100545 return rtc::scoped_ptr<rtcp::Fir>(fir);
niklase@google.com470e71d2011-07-07 08:21:25 +0000546}
547
548/*
549 0 1 2 3
550 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
551 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 | First | Number | PictureID |
553 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
554*/
Erik Språngf7c57762015-12-04 10:40:35 +0100555rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSLI(const RtcpContext& ctx) {
556 rtcp::Sli* sli = new rtcp::Sli();
557 sli->From(ssrc_);
558 sli->To(remote_ssrc_);
sprang0365a272015-08-11 01:02:37 -0700559 // Crop picture id to 6 least significant bits.
Erik Språngf7c57762015-12-04 10:40:35 +0100560 sli->WithPictureId(ctx.picture_id_ & 0x3F);
561 sli->WithFirstMb(0);
562 sli->WithNumberOfMb(0x1FFF); // 13 bits, only ones for now.
sprang0365a272015-08-11 01:02:37 -0700563
Erik Språngf7c57762015-12-04 10:40:35 +0100564 return rtc::scoped_ptr<rtcp::Sli>(sli);
niklase@google.com470e71d2011-07-07 08:21:25 +0000565}
566
567/*
568 0 1 2 3
569 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
570 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571 | PB |0| Payload Type| Native RPSI bit string |
572 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
573 | defined per codec ... | Padding (0) |
574 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
575*/
576/*
577* Note: not generic made for VP8
578*/
Erik Språngf7c57762015-12-04 10:40:35 +0100579rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildRPSI(
580 const RtcpContext& ctx) {
581 if (ctx.feedback_state_.send_payload_type == 0xFF)
582 return nullptr;
Erik Språng242e22b2015-05-11 10:17:43 +0200583
Erik Språngf7c57762015-12-04 10:40:35 +0100584 rtcp::Rpsi* rpsi = new rtcp::Rpsi();
585 rpsi->From(ssrc_);
586 rpsi->To(remote_ssrc_);
587 rpsi->WithPayloadType(ctx.feedback_state_.send_payload_type);
588 rpsi->WithPictureId(ctx.picture_id_);
sprangcf7f54d2015-08-13 04:37:42 -0700589
Erik Språngf7c57762015-12-04 10:40:35 +0100590 return rtc::scoped_ptr<rtcp::Rpsi>(rpsi);
niklase@google.com470e71d2011-07-07 08:21:25 +0000591}
592
Erik Språngf7c57762015-12-04 10:40:35 +0100593rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildREMB(
594 const RtcpContext& ctx) {
595 rtcp::Remb* remb = new rtcp::Remb();
596 remb->From(ssrc_);
sprangdd4edc52015-08-21 04:21:51 -0700597 for (uint32_t ssrc : remb_ssrcs_)
Erik Språngf7c57762015-12-04 10:40:35 +0100598 remb->AppliesTo(ssrc);
599 remb->WithBitrateBps(remb_bitrate_);
Erik Språng61be2a42015-04-27 13:32:52 +0200600
Erik Språng242e22b2015-05-11 10:17:43 +0200601 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
602 "RTCPSender::REMB");
603
Erik Språngf7c57762015-12-04 10:40:35 +0100604 return rtc::scoped_ptr<rtcp::Remb>(remb);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000605}
606
Erik Språng61be2a42015-04-27 13:32:52 +0200607void RTCPSender::SetTargetBitrate(unsigned int target_bitrate) {
Erik Språng242e22b2015-05-11 10:17:43 +0200608 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
609 tmmbr_send_ = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +0000610}
611
Erik Språngf7c57762015-12-04 10:40:35 +0100612rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBR(
613 const RtcpContext& ctx) {
614 if (ctx.feedback_state_.module == nullptr)
615 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200616 // Before sending the TMMBR check the received TMMBN, only an owner is
617 // allowed to raise the bitrate:
618 // * If the sender is an owner of the TMMBN -> send TMMBR
619 // * If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
niklase@google.com470e71d2011-07-07 08:21:25 +0000620
Erik Språng61be2a42015-04-27 13:32:52 +0200621 // get current bounding set from RTCP receiver
622 bool tmmbrOwner = false;
623 // store in candidateSet, allocates one extra slot
Erik Språng242e22b2015-05-11 10:17:43 +0200624 TMMBRSet* candidateSet = tmmbr_help_.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000625
Erik Språng242e22b2015-05-11 10:17:43 +0200626 // holding critical_section_rtcp_sender_ while calling RTCPreceiver which
627 // will accuire criticalSectionRTCPReceiver_ is a potental deadlock but
Erik Språng61be2a42015-04-27 13:32:52 +0200628 // since RTCPreceiver is not doing the reverse we should be fine
629 int32_t lengthOfBoundingSet =
danilchap6db6cdc2015-12-15 02:54:47 -0800630 ctx.feedback_state_.module->BoundingSet(&tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +0000631
Erik Språng61be2a42015-04-27 13:32:52 +0200632 if (lengthOfBoundingSet > 0) {
633 for (int32_t i = 0; i < lengthOfBoundingSet; i++) {
Erik Språng242e22b2015-05-11 10:17:43 +0200634 if (candidateSet->Tmmbr(i) == tmmbr_send_ &&
635 candidateSet->PacketOH(i) == packet_oh_send_) {
Erik Språngf7c57762015-12-04 10:40:35 +0100636 // Do not send the same tuple.
637 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200638 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 }
Erik Språng61be2a42015-04-27 13:32:52 +0200640 if (!tmmbrOwner) {
641 // use received bounding set as candidate set
642 // add current tuple
Erik Språng242e22b2015-05-11 10:17:43 +0200643 candidateSet->SetEntry(lengthOfBoundingSet, tmmbr_send_, packet_oh_send_,
644 ssrc_);
Erik Språng61be2a42015-04-27 13:32:52 +0200645 int numCandidates = lengthOfBoundingSet + 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000646
Erik Språng61be2a42015-04-27 13:32:52 +0200647 // find bounding set
Erik Språngf7c57762015-12-04 10:40:35 +0100648 TMMBRSet* boundingSet = nullptr;
Erik Språng242e22b2015-05-11 10:17:43 +0200649 int numBoundingSet = tmmbr_help_.FindTMMBRBoundingSet(boundingSet);
Erik Språng61be2a42015-04-27 13:32:52 +0200650 if (numBoundingSet > 0 || numBoundingSet <= numCandidates)
Erik Språng242e22b2015-05-11 10:17:43 +0200651 tmmbrOwner = tmmbr_help_.IsOwner(ssrc_, numBoundingSet);
Erik Språng61be2a42015-04-27 13:32:52 +0200652 if (!tmmbrOwner) {
Erik Språngf7c57762015-12-04 10:40:35 +0100653 // Did not enter bounding set, no meaning to send this request.
654 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200655 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 }
Erik Språng61be2a42015-04-27 13:32:52 +0200657 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
Erik Språngf7c57762015-12-04 10:40:35 +0100659 if (!tmmbr_send_)
660 return nullptr;
sprang81a3e602015-08-21 05:30:11 -0700661
Erik Språngf7c57762015-12-04 10:40:35 +0100662 rtcp::Tmmbr* tmmbr = new rtcp::Tmmbr();
663 tmmbr->From(ssrc_);
664 tmmbr->To(remote_ssrc_);
665 tmmbr->WithBitrateKbps(tmmbr_send_);
666 tmmbr->WithOverhead(packet_oh_send_);
667
668 return rtc::scoped_ptr<rtcp::Tmmbr>(tmmbr);
Erik Språng61be2a42015-04-27 13:32:52 +0200669}
670
Erik Språngf7c57762015-12-04 10:40:35 +0100671rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBN(
672 const RtcpContext& ctx) {
Erik Språng242e22b2015-05-11 10:17:43 +0200673 TMMBRSet* boundingSet = tmmbr_help_.BoundingSetToSend();
Erik Språngf7c57762015-12-04 10:40:35 +0100674 if (boundingSet == nullptr)
675 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200676
Erik Språngf7c57762015-12-04 10:40:35 +0100677 rtcp::Tmmbn* tmmbn = new rtcp::Tmmbn();
678 tmmbn->From(ssrc_);
sprangd83df502015-08-27 01:05:08 -0700679 for (uint32_t i = 0; i < boundingSet->lengthOfSet(); i++) {
680 if (boundingSet->Tmmbr(i) > 0) {
Erik Språngf7c57762015-12-04 10:40:35 +0100681 tmmbn->WithTmmbr(boundingSet->Ssrc(i), boundingSet->Tmmbr(i),
682 boundingSet->PacketOH(i));
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +0000683 }
Erik Språng61be2a42015-04-27 13:32:52 +0200684 }
sprangd83df502015-08-27 01:05:08 -0700685
Erik Språngf7c57762015-12-04 10:40:35 +0100686 return rtc::scoped_ptr<rtcp::Tmmbn>(tmmbn);
niklase@google.com470e71d2011-07-07 08:21:25 +0000687}
688
Erik Språngf7c57762015-12-04 10:40:35 +0100689rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildAPP(const RtcpContext& ctx) {
690 rtcp::App* app = new rtcp::App();
691 app->From(ssrc_);
692 app->WithSubType(app_sub_type_);
693 app->WithName(app_name_);
694 app->WithData(app_data_.get(), app_length_);
Erik Språng521875a2015-09-01 10:11:16 +0200695
Erik Språngf7c57762015-12-04 10:40:35 +0100696 return rtc::scoped_ptr<rtcp::App>(app);
Erik Språng61be2a42015-04-27 13:32:52 +0200697}
698
Erik Språngf7c57762015-12-04 10:40:35 +0100699rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK(
700 const RtcpContext& ctx) {
701 rtcp::Nack* nack = new rtcp::Nack();
702 nack->From(ssrc_);
703 nack->To(remote_ssrc_);
704 nack->WithList(ctx.nack_list_, ctx.nack_size_);
Erik Språng61be2a42015-04-27 13:32:52 +0200705
706 // Report stats.
707 NACKStringBuilder stringBuilder;
Erik Språngf7c57762015-12-04 10:40:35 +0100708 for (int idx = 0; idx < ctx.nack_size_; ++idx) {
709 stringBuilder.PushNACK(ctx.nack_list_[idx]);
710 nack_stats_.ReportRequest(ctx.nack_list_[idx]);
Erik Språng61be2a42015-04-27 13:32:52 +0200711 }
Erik Språng61be2a42015-04-27 13:32:52 +0200712 packet_type_counter_.nack_requests = nack_stats_.requests();
713 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
Erik Språng242e22b2015-05-11 10:17:43 +0200714
715 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
716 "RTCPSender::NACK", "nacks",
717 TRACE_STR_COPY(stringBuilder.GetResult().c_str()));
718 ++packet_type_counter_.nack_packets;
719 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_NACKCount",
720 ssrc_, packet_type_counter_.nack_packets);
721
Erik Språngf7c57762015-12-04 10:40:35 +0100722 return rtc::scoped_ptr<rtcp::Nack>(nack);
Erik Språng61be2a42015-04-27 13:32:52 +0200723}
724
Erik Språngf7c57762015-12-04 10:40:35 +0100725rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildBYE(const RtcpContext& ctx) {
726 rtcp::Bye* bye = new rtcp::Bye();
727 bye->From(ssrc_);
sprangd8ee4f92015-08-24 03:25:19 -0700728 for (uint32_t csrc : csrcs_)
Erik Språngf7c57762015-12-04 10:40:35 +0100729 bye->WithCsrc(csrc);
sprangd8ee4f92015-08-24 03:25:19 -0700730
Erik Språngf7c57762015-12-04 10:40:35 +0100731 return rtc::scoped_ptr<rtcp::Bye>(bye);
niklase@google.com470e71d2011-07-07 08:21:25 +0000732}
733
Erik Språngf7c57762015-12-04 10:40:35 +0100734rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildReceiverReferenceTime(
735 const RtcpContext& ctx) {
Erik Språng61be2a42015-04-27 13:32:52 +0200736 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000737 last_xr_rr_.erase(last_xr_rr_.begin());
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000738 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
Erik Språngf7c57762015-12-04 10:40:35 +0100739 RTCPUtility::MidNtp(ctx.ntp_sec_, ctx.ntp_frac_),
740 Clock::NtpToMs(ctx.ntp_sec_, ctx.ntp_frac_)));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000741
Erik Språngf7c57762015-12-04 10:40:35 +0100742 rtcp::Xr* xr = new rtcp::Xr();
743 xr->From(ssrc_);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000744
Erik Språngca28fdc2015-08-31 14:00:50 +0200745 rtcp::Rrtr rrtr;
Danil Chapovalovfc47ed62015-12-07 14:46:35 +0100746 rrtr.WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000747
Erik Språngf7c57762015-12-04 10:40:35 +0100748 xr->WithRrtr(&rrtr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000749
Erik Språngca28fdc2015-08-31 14:00:50 +0200750 // TODO(sprang): Merge XR report sending to contain all of RRTR, DLRR, VOIP?
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000751
Erik Språngf7c57762015-12-04 10:40:35 +0100752 return rtc::scoped_ptr<rtcp::Xr>(xr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000753}
754
Erik Språngf7c57762015-12-04 10:40:35 +0100755rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildDlrr(
756 const RtcpContext& ctx) {
757 rtcp::Xr* xr = new rtcp::Xr();
758 xr->From(ssrc_);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000759
Erik Språngca28fdc2015-08-31 14:00:50 +0200760 rtcp::Dlrr dlrr;
Erik Språngf7c57762015-12-04 10:40:35 +0100761 const RtcpReceiveTimeInfo& info = ctx.feedback_state_.last_xr_rr;
Erik Språngca28fdc2015-08-31 14:00:50 +0200762 dlrr.WithDlrrItem(info.sourceSSRC, info.lastRR, info.delaySinceLastRR);
763
Erik Språngf7c57762015-12-04 10:40:35 +0100764 xr->WithDlrr(&dlrr);
Erik Språngca28fdc2015-08-31 14:00:50 +0200765
Erik Språngf7c57762015-12-04 10:40:35 +0100766 return rtc::scoped_ptr<rtcp::Xr>(xr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000767}
768
Erik Språng242e22b2015-05-11 10:17:43 +0200769// TODO(sprang): Add a unit test for this, or remove if the code isn't used.
Erik Språngf7c57762015-12-04 10:40:35 +0100770rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildVoIPMetric(
771 const RtcpContext& context) {
772 rtcp::Xr* xr = new rtcp::Xr();
773 xr->From(ssrc_);
Erik Språngca28fdc2015-08-31 14:00:50 +0200774
775 rtcp::VoipMetric voip;
776 voip.To(remote_ssrc_);
danilchap91941ae2015-12-15 07:06:36 -0800777 voip.WithVoipMetric(xr_voip_metric_);
Erik Språngca28fdc2015-08-31 14:00:50 +0200778
Erik Språngf7c57762015-12-04 10:40:35 +0100779 xr->WithVoipMetric(&voip);
Erik Språngca28fdc2015-08-31 14:00:50 +0200780
Erik Språngf7c57762015-12-04 10:40:35 +0100781 return rtc::scoped_ptr<rtcp::Xr>(xr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000782}
783
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000784int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
Erik Språng242e22b2015-05-11 10:17:43 +0200785 RTCPPacketType packetType,
786 int32_t nack_size,
787 const uint16_t* nack_list,
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000788 bool repeat,
789 uint64_t pictureID) {
Erik Språng242e22b2015-05-11 10:17:43 +0200790 return SendCompoundRTCP(
791 feedback_state, std::set<RTCPPacketType>(&packetType, &packetType + 1),
792 nack_size, nack_list, repeat, pictureID);
793}
794
795int32_t RTCPSender::SendCompoundRTCP(
796 const FeedbackState& feedback_state,
Erik Språngf7c57762015-12-04 10:40:35 +0100797 const std::set<RTCPPacketType>& packet_types,
Erik Språng242e22b2015-05-11 10:17:43 +0200798 int32_t nack_size,
799 const uint16_t* nack_list,
800 bool repeat,
801 uint64_t pictureID) {
Erik Språngf7c57762015-12-04 10:40:35 +0100802 PacketContainer container(transport_);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000803 {
Erik Språng242e22b2015-05-11 10:17:43 +0200804 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
pbosda903ea2015-10-02 02:36:56 -0700805 if (method_ == RtcpMode::kOff) {
Erik Språng61be2a42015-04-27 13:32:52 +0200806 LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
807 return -1;
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +0000808 }
Erik Språngf7c57762015-12-04 10:40:35 +0100809
810 // We need to send our NTP even if we haven't received any reports.
811 uint32_t ntp_sec;
812 uint32_t ntp_frac;
813 clock_->CurrentNtp(ntp_sec, ntp_frac);
814 RtcpContext context(feedback_state, nack_size, nack_list, repeat, pictureID,
815 ntp_sec, ntp_frac, &container);
816
817 PrepareReport(packet_types, feedback_state);
818
819 auto it = report_flags_.begin();
820 while (it != report_flags_.end()) {
821 auto builder_it = builders_.find(it->type);
822 RTC_DCHECK(builder_it != builders_.end());
823 if (it->is_volatile) {
824 report_flags_.erase(it++);
825 } else {
826 ++it;
827 }
828
829 BuilderFunc func = builder_it->second;
830 rtc::scoped_ptr<rtcp::RtcpPacket> packet = (this->*func)(context);
831 if (packet.get() == nullptr)
832 return -1;
833 container.Append(packet.release());
834 }
835
836 if (packet_type_counter_observer_ != nullptr) {
837 packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
838 remote_ssrc_, packet_type_counter_);
839 }
840
841 RTC_DCHECK(AllVolatileFlagsConsumed());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000842 }
Erik Språng61be2a42015-04-27 13:32:52 +0200843
Erik Språngf7c57762015-12-04 10:40:35 +0100844 size_t bytes_sent = container.SendPackets();
845 return bytes_sent == 0 ? -1 : 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000846}
847
Erik Språngf7c57762015-12-04 10:40:35 +0100848void RTCPSender::PrepareReport(const std::set<RTCPPacketType>& packetTypes,
849 const FeedbackState& feedback_state) {
Erik Språng242e22b2015-05-11 10:17:43 +0200850 // Add all flags as volatile. Non volatile entries will not be overwritten
851 // and all new volatile flags added will be consumed by the end of this call.
852 SetFlags(packetTypes, true);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000853
Erik Språng61be2a42015-04-27 13:32:52 +0200854 if (packet_type_counter_.first_packet_time_ms == -1)
Erik Språng242e22b2015-05-11 10:17:43 +0200855 packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds();
Erik Språng61be2a42015-04-27 13:32:52 +0200856
Erik Språng242e22b2015-05-11 10:17:43 +0200857 bool generate_report;
858 if (IsFlagPresent(kRtcpSr) || IsFlagPresent(kRtcpRr)) {
859 // Report type already explicitly set, don't automatically populate.
860 generate_report = true;
henrikg91d6ede2015-09-17 00:24:34 -0700861 RTC_DCHECK(ConsumeFlag(kRtcpReport) == false);
Erik Språng242e22b2015-05-11 10:17:43 +0200862 } else {
863 generate_report =
pbosda903ea2015-10-02 02:36:56 -0700864 (ConsumeFlag(kRtcpReport) && method_ == RtcpMode::kReducedSize) ||
865 method_ == RtcpMode::kCompound;
Erik Språng242e22b2015-05-11 10:17:43 +0200866 if (generate_report)
867 SetFlag(sending_ ? kRtcpSr : kRtcpRr, true);
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000868 }
869
Erik Språng0ea42d32015-06-25 14:46:16 +0200870 if (IsFlagPresent(kRtcpSr) || (IsFlagPresent(kRtcpRr) && !cname_.empty()))
Erik Språng242e22b2015-05-11 10:17:43 +0200871 SetFlag(kRtcpSdes, true);
872
Erik Språng242e22b2015-05-11 10:17:43 +0200873 if (generate_report) {
874 if (!sending_ && xr_send_receiver_reference_time_enabled_)
875 SetFlag(kRtcpXrReceiverReferenceTime, true);
Erik Språng61be2a42015-04-27 13:32:52 +0200876 if (feedback_state.has_last_xr_rr)
Erik Språng242e22b2015-05-11 10:17:43 +0200877 SetFlag(kRtcpXrDlrrReportBlock, true);
878
879 // generate next time to send an RTCP report
danilchap47a740b2015-12-15 00:30:07 -0800880 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000881
danilchap47a740b2015-12-15 00:30:07 -0800882 if (!audio_) {
Erik Språng242e22b2015-05-11 10:17:43 +0200883 if (sending_) {
Erik Språng61be2a42015-04-27 13:32:52 +0200884 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
885 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
886 if (send_bitrate_kbit != 0)
887 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000888 }
Erik Språng61be2a42015-04-27 13:32:52 +0200889 if (minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
890 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
Erik Språng61be2a42015-04-27 13:32:52 +0200891 }
danilchap47a740b2015-12-15 00:30:07 -0800892 // The interval between RTCP packets is varied randomly over the
893 // range [1/2,3/2] times the calculated interval.
894 uint32_t timeToNext =
895 random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2);
Erik Språng242e22b2015-05-11 10:17:43 +0200896 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000897
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000898 StatisticianMap statisticians =
899 receive_statistics_->GetActiveStatisticians();
danilchapa72e7342015-12-22 08:07:45 -0800900 RTC_DCHECK(report_blocks_.empty());
901 for (auto& it : statisticians) {
902 AddReportBlock(feedback_state, it.first, it.second);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000903 }
904 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000905}
906
danilchapa72e7342015-12-22 08:07:45 -0800907bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state,
908 uint32_t ssrc,
909 StreamStatistician* statistician) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000910 // Do we have receive statistics to send?
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000911 RtcpStatistics stats;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000912 if (!statistician->GetStatistics(&stats, true))
913 return false;
danilchapa72e7342015-12-22 08:07:45 -0800914
915 if (report_blocks_.size() >= RTCP_MAX_REPORT_BLOCKS) {
916 LOG(LS_WARNING) << "Too many report blocks.";
917 return false;
918 }
919 RTC_DCHECK(report_blocks_.find(ssrc) == report_blocks_.end());
920 rtcp::ReportBlock* block = &report_blocks_[ssrc];
921 block->To(ssrc);
922 block->WithFractionLost(stats.fraction_lost);
923 if (!block->WithCumulativeLost(stats.cumulative_lost)) {
924 report_blocks_.erase(ssrc);
925 LOG(LS_WARNING) << "Cumulative lost is oversized.";
926 return false;
927 }
928 block->WithExtHighestSeqNum(stats.extended_max_sequence_number);
929 block->WithJitter(stats.jitter);
930 block->WithLastSr(feedback_state.remote_sr);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000931
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200932 // TODO(sprang): Do we really need separate time stamps for each report?
933 // Get our NTP as late as possible to avoid a race.
934 uint32_t ntp_secs;
935 uint32_t ntp_frac;
936 clock_->CurrentNtp(ntp_secs, ntp_frac);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000937
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200938 // Delay since last received report.
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000939 if ((feedback_state.last_rr_ntp_secs != 0) ||
940 (feedback_state.last_rr_ntp_frac != 0)) {
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200941 // Get the 16 lowest bits of seconds and the 16 highest bits of fractions.
942 uint32_t now = ntp_secs & 0x0000FFFF;
Erik Språng61be2a42015-04-27 13:32:52 +0200943 now <<= 16;
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200944 now += (ntp_frac & 0xffff0000) >> 16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000945
Erik Språng61be2a42015-04-27 13:32:52 +0200946 uint32_t receiveTime = feedback_state.last_rr_ntp_secs & 0x0000FFFF;
947 receiveTime <<= 16;
948 receiveTime += (feedback_state.last_rr_ntp_frac & 0xffff0000) >> 16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000949
danilchapa72e7342015-12-22 08:07:45 -0800950 block->WithDelayLastSr(now - receiveTime);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000951 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000952 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000953}
954
pbos@webrtc.org9334ac22014-11-24 08:25:50 +0000955void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
956 assert(csrcs.size() <= kRtpCsrcSize);
Erik Språng242e22b2015-05-11 10:17:43 +0200957 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
pbos@webrtc.org9334ac22014-11-24 08:25:50 +0000958 csrcs_ = csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000959}
960
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000961int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
962 uint32_t name,
963 const uint8_t* data,
964 uint16_t length) {
Erik Språng61be2a42015-04-27 13:32:52 +0200965 if (length % 4 != 0) {
966 LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
967 return -1;
968 }
Erik Språng242e22b2015-05-11 10:17:43 +0200969 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000970
Erik Språng242e22b2015-05-11 10:17:43 +0200971 SetFlag(kRtcpApp, true);
972 app_sub_type_ = subType;
973 app_name_ = name;
974 app_data_.reset(new uint8_t[length]);
975 app_length_ = length;
976 memcpy(app_data_.get(), data, length);
Erik Språng61be2a42015-04-27 13:32:52 +0200977 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000978}
979
Erik Språng61be2a42015-04-27 13:32:52 +0200980int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
Erik Språng242e22b2015-05-11 10:17:43 +0200981 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
982 memcpy(&xr_voip_metric_, VoIPMetric, sizeof(RTCPVoIPMetric));
niklase@google.com470e71d2011-07-07 08:21:25 +0000983
Erik Språng242e22b2015-05-11 10:17:43 +0200984 SetFlag(kRtcpXrVoipMetric, true);
Erik Språng61be2a42015-04-27 13:32:52 +0200985 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000986}
987
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000988void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200989 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
990 xr_send_receiver_reference_time_enabled_ = enable;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000991}
992
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +0000993bool RTCPSender::RtcpXrReceiverReferenceTime() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200994 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
995 return xr_send_receiver_reference_time_enabled_;
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +0000996}
997
niklase@google.com470e71d2011-07-07 08:21:25 +0000998// no callbacks allowed inside this function
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000999int32_t RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
1000 uint32_t maxBitrateKbit) {
Erik Språng242e22b2015-05-11 10:17:43 +02001001 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001002
Erik Språng242e22b2015-05-11 10:17:43 +02001003 if (0 == tmmbr_help_.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit)) {
1004 SetFlag(kRtcpTmmbn, true);
Erik Språng61be2a42015-04-27 13:32:52 +02001005 return 0;
1006 }
1007 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001008}
Erik Språng61be2a42015-04-27 13:32:52 +02001009
Erik Språng242e22b2015-05-11 10:17:43 +02001010void RTCPSender::SetFlag(RTCPPacketType type, bool is_volatile) {
1011 report_flags_.insert(ReportFlag(type, is_volatile));
1012}
1013
1014void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
1015 bool is_volatile) {
1016 for (RTCPPacketType type : types)
1017 SetFlag(type, is_volatile);
1018}
1019
1020bool RTCPSender::IsFlagPresent(RTCPPacketType type) const {
1021 return report_flags_.find(ReportFlag(type, false)) != report_flags_.end();
1022}
1023
1024bool RTCPSender::ConsumeFlag(RTCPPacketType type, bool forced) {
1025 auto it = report_flags_.find(ReportFlag(type, false));
1026 if (it == report_flags_.end())
1027 return false;
1028 if (it->is_volatile || forced)
1029 report_flags_.erase((it));
1030 return true;
1031}
1032
1033bool RTCPSender::AllVolatileFlagsConsumed() const {
1034 for (const ReportFlag& flag : report_flags_) {
1035 if (flag.is_volatile)
1036 return false;
1037 }
1038 return true;
1039}
1040
sprang233bd872015-09-08 13:25:16 -07001041bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
sprang233bd872015-09-08 13:25:16 -07001042 class Sender : public rtcp::RtcpPacket::PacketReadyCallback {
1043 public:
danilchap6db6cdc2015-12-15 02:54:47 -08001044 explicit Sender(Transport* transport)
Peter Boströmac547a62015-09-17 23:03:57 +02001045 : transport_(transport), send_failure_(false) {}
sprang233bd872015-09-08 13:25:16 -07001046
1047 void OnPacketReady(uint8_t* data, size_t length) override {
pbos2d566682015-09-28 09:59:31 -07001048 if (!transport_->SendRtcp(data, length))
sprang233bd872015-09-08 13:25:16 -07001049 send_failure_ = true;
1050 }
1051
1052 Transport* const transport_;
sprang233bd872015-09-08 13:25:16 -07001053 bool send_failure_;
sprang86fd9ed2015-09-29 04:45:43 -07001054 } sender(transport_);
sprang233bd872015-09-08 13:25:16 -07001055
1056 uint8_t buffer[IP_PACKET_SIZE];
1057 return packet.BuildExternalBuffer(buffer, IP_PACKET_SIZE, &sender) &&
1058 !sender.send_failure_;
1059}
1060
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001061} // namespace webrtc