blob: a4f6f3923b87c5ff4c6eaaf172f8b1509b9b4bb1 [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"
sprang233bd872015-09-08 13:25:16 -070030#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
tommie4f96502015-10-20 23:00:48 -070031#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010032#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
pwestin@webrtc.org741da942011-09-20 13:52:04 +000033
niklase@google.com470e71d2011-07-07 08:21:25 +000034namespace webrtc {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000035
36using RTCPUtility::RTCPCnameInformation;
37
Erik Språng61be2a42015-04-27 13:32:52 +020038NACKStringBuilder::NACKStringBuilder()
danilchap162abd32015-12-10 02:39:40 -080039 : stream_(""), count_(0), prevNack_(0), consecutive_(false) {}
edjee@google.com79b02892013-04-04 19:43:34 +000040
pbos@webrtc.orgf3e4cee2013-07-31 15:17:19 +000041NACKStringBuilder::~NACKStringBuilder() {}
42
danilchap162abd32015-12-10 02:39:40 -080043void NACKStringBuilder::PushNACK(uint16_t nack) {
Erik Språng242e22b2015-05-11 10:17:43 +020044 if (count_ == 0) {
45 stream_ << nack;
46 } else if (nack == prevNack_ + 1) {
47 consecutive_ = true;
Erik Språng61be2a42015-04-27 13:32:52 +020048 } else {
Erik Språng242e22b2015-05-11 10:17:43 +020049 if (consecutive_) {
50 stream_ << "-" << prevNack_;
51 consecutive_ = false;
edjee@google.com79b02892013-04-04 19:43:34 +000052 }
Erik Språng242e22b2015-05-11 10:17:43 +020053 stream_ << "," << nack;
Erik Språng61be2a42015-04-27 13:32:52 +020054 }
Erik Språng242e22b2015-05-11 10:17:43 +020055 count_++;
56 prevNack_ = nack;
edjee@google.com79b02892013-04-04 19:43:34 +000057}
58
Erik Språng61be2a42015-04-27 13:32:52 +020059std::string NACKStringBuilder::GetResult() {
Erik Språng242e22b2015-05-11 10:17:43 +020060 if (consecutive_) {
61 stream_ << "-" << prevNack_;
62 consecutive_ = false;
Erik Språng61be2a42015-04-27 13:32:52 +020063 }
Erik Språng242e22b2015-05-11 10:17:43 +020064 return stream_.str();
edjee@google.com79b02892013-04-04 19:43:34 +000065}
66
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000067RTCPSender::FeedbackState::FeedbackState()
68 : send_payload_type(0),
69 frequency_hz(0),
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +000070 packets_sent(0),
71 media_bytes_sent(0),
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000072 send_bitrate(0),
73 last_rr_ntp_secs(0),
74 last_rr_ntp_frac(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000075 remote_sr(0),
Erik Språng61be2a42015-04-27 13:32:52 +020076 has_last_xr_rr(false),
danilchap162abd32015-12-10 02:39:40 -080077 module(nullptr) {}
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000078
Erik Språngf7c57762015-12-04 10:40:35 +010079class PacketContainer : public rtcp::Empty,
80 public rtcp::RtcpPacket::PacketReadyCallback {
81 public:
82 explicit PacketContainer(Transport* transport)
83 : transport_(transport), bytes_sent_(0) {}
84 virtual ~PacketContainer() {
85 for (RtcpPacket* packet : appended_packets_)
86 delete packet;
87 }
88
89 void OnPacketReady(uint8_t* data, size_t length) override {
90 if (transport_->SendRtcp(data, length))
91 bytes_sent_ += length;
92 }
93
94 size_t SendPackets() {
95 rtcp::Empty::Build(this);
96 return bytes_sent_;
97 }
98
99 private:
100 Transport* transport_;
101 size_t bytes_sent_;
102};
103
104class RTCPSender::RtcpContext {
105 public:
Erik Språng242e22b2015-05-11 10:17:43 +0200106 RtcpContext(const FeedbackState& feedback_state,
107 int32_t nack_size,
108 const uint16_t* nack_list,
109 bool repeat,
110 uint64_t picture_id,
Erik Språngf7c57762015-12-04 10:40:35 +0100111 uint32_t ntp_sec,
112 uint32_t ntp_frac,
113 PacketContainer* container)
114 : feedback_state_(feedback_state),
115 nack_size_(nack_size),
116 nack_list_(nack_list),
117 repeat_(repeat),
118 picture_id_(picture_id),
119 ntp_sec_(ntp_sec),
120 ntp_frac_(ntp_frac),
121 container_(container) {}
Erik Språng242e22b2015-05-11 10:17:43 +0200122
Erik Språngf7c57762015-12-04 10:40:35 +0100123 virtual ~RtcpContext() {}
Erik Språng242e22b2015-05-11 10:17:43 +0200124
Erik Språngf7c57762015-12-04 10:40:35 +0100125 const FeedbackState& feedback_state_;
126 const int32_t nack_size_;
127 const uint16_t* nack_list_;
128 const bool repeat_;
129 const uint64_t picture_id_;
130 const uint32_t ntp_sec_;
131 const uint32_t ntp_frac_;
Erik Språng242e22b2015-05-11 10:17:43 +0200132
Erik Språngf7c57762015-12-04 10:40:35 +0100133 PacketContainer* const container_;
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200134};
135
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000136RTCPSender::RTCPSender(
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000137 bool audio,
138 Clock* clock,
139 ReceiveStatistics* receive_statistics,
sprang86fd9ed2015-09-29 04:45:43 -0700140 RtcpPacketTypeCounterObserver* packet_type_counter_observer,
141 Transport* outgoing_transport)
Peter Boströmac547a62015-09-17 23:03:57 +0200142 : audio_(audio),
Erik Språng242e22b2015-05-11 10:17:43 +0200143 clock_(clock),
danilchap47a740b2015-12-15 00:30:07 -0800144 random_(clock_->TimeInMicroseconds()),
pbosda903ea2015-10-02 02:36:56 -0700145 method_(RtcpMode::kOff),
sprang86fd9ed2015-09-29 04:45:43 -0700146 transport_(outgoing_transport),
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
Erik Språng242e22b2015-05-11 10:17:43 +0200148 critical_section_rtcp_sender_(
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000149 CriticalSectionWrapper::CreateCriticalSection()),
Erik Språng242e22b2015-05-11 10:17:43 +0200150 using_nack_(false),
151 sending_(false),
152 remb_enabled_(false),
Erik Språng242e22b2015-05-11 10:17:43 +0200153 next_time_to_send_rtcp_(0),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000154 start_timestamp_(0),
155 last_rtp_timestamp_(0),
156 last_frame_capture_time_ms_(-1),
Erik Språng242e22b2015-05-11 10:17:43 +0200157 ssrc_(0),
158 remote_ssrc_(0),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000159 receive_statistics_(receive_statistics),
niklase@google.com470e71d2011-07-07 08:21:25 +0000160
Erik Språng242e22b2015-05-11 10:17:43 +0200161 sequence_number_fir_(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000162
Erik Språng242e22b2015-05-11 10:17:43 +0200163 remb_bitrate_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
Erik Språng242e22b2015-05-11 10:17:43 +0200165 tmmbr_help_(),
166 tmmbr_send_(0),
167 packet_oh_send_(0),
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000168
Erik Språng242e22b2015-05-11 10:17:43 +0200169 app_sub_type_(0),
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200170 app_name_(0),
Erik Språng242e22b2015-05-11 10:17:43 +0200171 app_data_(nullptr),
172 app_length_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000173
Erik Språng242e22b2015-05-11 10:17:43 +0200174 xr_send_receiver_reference_time_enabled_(false),
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000175 packet_type_counter_observer_(packet_type_counter_observer) {
Erik Språng242e22b2015-05-11 10:17:43 +0200176 memset(last_send_report_, 0, sizeof(last_send_report_));
177 memset(last_rtcp_time_, 0, sizeof(last_rtcp_time_));
sprang86fd9ed2015-09-29 04:45:43 -0700178 RTC_DCHECK(transport_ != nullptr);
Erik Språng242e22b2015-05-11 10:17:43 +0200179
180 builders_[kRtcpSr] = &RTCPSender::BuildSR;
181 builders_[kRtcpRr] = &RTCPSender::BuildRR;
Erik Språng0ea42d32015-06-25 14:46:16 +0200182 builders_[kRtcpSdes] = &RTCPSender::BuildSDES;
Erik Språng242e22b2015-05-11 10:17:43 +0200183 builders_[kRtcpPli] = &RTCPSender::BuildPLI;
184 builders_[kRtcpFir] = &RTCPSender::BuildFIR;
185 builders_[kRtcpSli] = &RTCPSender::BuildSLI;
186 builders_[kRtcpRpsi] = &RTCPSender::BuildRPSI;
187 builders_[kRtcpRemb] = &RTCPSender::BuildREMB;
188 builders_[kRtcpBye] = &RTCPSender::BuildBYE;
189 builders_[kRtcpApp] = &RTCPSender::BuildAPP;
190 builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
191 builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
192 builders_[kRtcpNack] = &RTCPSender::BuildNACK;
193 builders_[kRtcpXrVoipMetric] = &RTCPSender::BuildVoIPMetric;
194 builders_[kRtcpXrReceiverReferenceTime] =
195 &RTCPSender::BuildReceiverReferenceTime;
196 builders_[kRtcpXrDlrrReportBlock] = &RTCPSender::BuildDlrr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197}
198
danilchap162abd32015-12-10 02:39:40 -0800199RTCPSender::~RTCPSender() {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000200
pbosda903ea2015-10-02 02:36:56 -0700201RtcpMode RTCPSender::Status() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200202 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
203 return method_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000204}
205
pbosda903ea2015-10-02 02:36:56 -0700206void RTCPSender::SetRTCPStatus(RtcpMode method) {
Erik Språng242e22b2015-05-11 10:17:43 +0200207 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
208 method_ = method;
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000209
pbosda903ea2015-10-02 02:36:56 -0700210 if (method == RtcpMode::kOff)
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000211 return;
Erik Språng242e22b2015-05-11 10:17:43 +0200212 next_time_to_send_rtcp_ =
213 clock_->TimeInMilliseconds() +
214 (audio_ ? RTCP_INTERVAL_AUDIO_MS / 2 : RTCP_INTERVAL_VIDEO_MS / 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000215}
216
Erik Språng61be2a42015-04-27 13:32:52 +0200217bool RTCPSender::Sending() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200218 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
219 return sending_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000220}
221
Erik Språng61be2a42015-04-27 13:32:52 +0200222int32_t RTCPSender::SetSendingStatus(const FeedbackState& feedback_state,
223 bool sending) {
224 bool sendRTCPBye = false;
225 {
Erik Språng242e22b2015-05-11 10:17:43 +0200226 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000227
pbosda903ea2015-10-02 02:36:56 -0700228 if (method_ != RtcpMode::kOff) {
Erik Språng242e22b2015-05-11 10:17:43 +0200229 if (sending == false && sending_ == true) {
Erik Språng61be2a42015-04-27 13:32:52 +0200230 // Trigger RTCP bye
231 sendRTCPBye = true;
232 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 }
Erik Språng242e22b2015-05-11 10:17:43 +0200234 sending_ = sending;
Erik Språng61be2a42015-04-27 13:32:52 +0200235 }
236 if (sendRTCPBye)
237 return SendRTCP(feedback_state, kRtcpBye);
238 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
240
Erik Språng61be2a42015-04-27 13:32:52 +0200241bool RTCPSender::REMB() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200242 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
243 return remb_enabled_;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000244}
245
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000246void RTCPSender::SetREMBStatus(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200247 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
248 remb_enabled_ = enable;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000249}
250
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000251void RTCPSender::SetREMBData(uint32_t bitrate,
252 const std::vector<uint32_t>& ssrcs) {
Erik Språng242e22b2015-05-11 10:17:43 +0200253 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
254 remb_bitrate_ = bitrate;
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000255 remb_ssrcs_ = ssrcs;
stefan@webrtc.org4ef438e2014-07-11 09:55:30 +0000256
Erik Språng242e22b2015-05-11 10:17:43 +0200257 if (remb_enabled_)
258 SetFlag(kRtcpRemb, false);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000259 // Send a REMB immediately if we have a new REMB. The frequency of REMBs is
260 // throttled by the caller.
Erik Språng242e22b2015-05-11 10:17:43 +0200261 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds();
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000262}
263
Erik Språng61be2a42015-04-27 13:32:52 +0200264bool RTCPSender::TMMBR() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200265 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
266 return IsFlagPresent(RTCPPacketType::kRtcpTmmbr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000267}
268
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000269void RTCPSender::SetTMMBRStatus(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200270 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
271 if (enable) {
272 SetFlag(RTCPPacketType::kRtcpTmmbr, false);
273 } else {
274 ConsumeFlag(RTCPPacketType::kRtcpTmmbr, true);
275 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000276}
277
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000278void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
Erik Språng242e22b2015-05-11 10:17:43 +0200279 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000280 start_timestamp_ = start_timestamp;
281}
282
283void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
284 int64_t capture_time_ms) {
Erik Språng242e22b2015-05-11 10:17:43 +0200285 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000286 last_rtp_timestamp_ = rtp_timestamp;
287 if (capture_time_ms < 0) {
288 // We don't currently get a capture time from VoiceEngine.
Erik Språng242e22b2015-05-11 10:17:43 +0200289 last_frame_capture_time_ms_ = clock_->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000290 } else {
291 last_frame_capture_time_ms_ = capture_time_ms;
292 }
293}
294
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000295void RTCPSender::SetSSRC(uint32_t ssrc) {
Erik Språng242e22b2015-05-11 10:17:43 +0200296 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000297
Erik Språng242e22b2015-05-11 10:17:43 +0200298 if (ssrc_ != 0) {
Erik Språng61be2a42015-04-27 13:32:52 +0200299 // not first SetSSRC, probably due to a collision
300 // schedule a new RTCP report
301 // make sure that we send a RTP packet
Erik Språng242e22b2015-05-11 10:17:43 +0200302 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + 100;
Erik Språng61be2a42015-04-27 13:32:52 +0200303 }
Erik Språng242e22b2015-05-11 10:17:43 +0200304 ssrc_ = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000305}
306
Erik Språng61be2a42015-04-27 13:32:52 +0200307void RTCPSender::SetRemoteSSRC(uint32_t ssrc) {
Erik Språng242e22b2015-05-11 10:17:43 +0200308 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
309 remote_ssrc_ = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000310}
311
Peter Boström9ba52f82015-06-01 14:12:28 +0200312int32_t RTCPSender::SetCNAME(const char* c_name) {
313 if (!c_name)
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000314 return -1;
315
henrikg91d6ede2015-09-17 00:24:34 -0700316 RTC_DCHECK_LT(strlen(c_name), static_cast<size_t>(RTCP_CNAME_SIZE));
Erik Språng242e22b2015-05-11 10:17:43 +0200317 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200318 cname_ = c_name;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000319 return 0;
320}
321
Erik Språng0ea42d32015-06-25 14:46:16 +0200322int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC, const char* c_name) {
323 assert(c_name);
henrikg91d6ede2015-09-17 00:24:34 -0700324 RTC_DCHECK_LT(strlen(c_name), static_cast<size_t>(RTCP_CNAME_SIZE));
Erik Språng242e22b2015-05-11 10:17:43 +0200325 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200326 if (csrc_cnames_.size() >= kRtpCsrcSize)
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000327 return -1;
Erik Språng0ea42d32015-06-25 14:46:16 +0200328
329 csrc_cnames_[SSRC] = c_name;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000330 return 0;
331}
332
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000333int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
Erik Språng242e22b2015-05-11 10:17:43 +0200334 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200335 auto it = csrc_cnames_.find(SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000336
Erik Språng242e22b2015-05-11 10:17:43 +0200337 if (it == csrc_cnames_.end())
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000338 return -1;
Erik Språng61be2a42015-04-27 13:32:52 +0200339
Erik Språng242e22b2015-05-11 10:17:43 +0200340 csrc_cnames_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000341 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000342}
343
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000344bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
danilchap162abd32015-12-10 02:39:40 -0800345 /*
346 For audio we use a fix 5 sec interval
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
danilchap162abd32015-12-10 02:39:40 -0800348 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
349 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but
350 that should be extremely rare
niklase@google.com470e71d2011-07-07 08:21:25 +0000351
352
danilchap162abd32015-12-10 02:39:40 -0800353 From RFC 3550
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
danilchap162abd32015-12-10 02:39:40 -0800355 MAX RTCP BW is 5% if the session BW
356 A send report is approximately 65 bytes inc CNAME
357 A receiver report is approximately 28 bytes
niklase@google.com470e71d2011-07-07 08:21:25 +0000358
danilchap162abd32015-12-10 02:39:40 -0800359 The RECOMMENDED value for the reduced minimum in seconds is 360
360 divided by the session bandwidth in kilobits/second. This minimum
361 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
niklase@google.com470e71d2011-07-07 08:21:25 +0000362
danilchap162abd32015-12-10 02:39:40 -0800363 If the participant has not yet sent an RTCP packet (the variable
364 initial is true), the constant Tmin is set to 2.5 seconds, else it
365 is set to 5 seconds.
niklase@google.com470e71d2011-07-07 08:21:25 +0000366
danilchap162abd32015-12-10 02:39:40 -0800367 The interval between RTCP packets is varied randomly over the
368 range [0.5,1.5] times the calculated interval to avoid unintended
369 synchronization of all participants
niklase@google.com470e71d2011-07-07 08:21:25 +0000370
danilchap162abd32015-12-10 02:39:40 -0800371 if we send
372 If the participant is a sender (we_sent true), the constant C is
373 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
374 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
375 number of senders.
niklase@google.com470e71d2011-07-07 08:21:25 +0000376
danilchap162abd32015-12-10 02:39:40 -0800377 if we receive only
378 If we_sent is not true, the constant C is set
379 to the average RTCP packet size divided by 75% of the RTCP
380 bandwidth. The constant n is set to the number of receivers
381 (members - senders). If the number of senders is greater than
382 25%, senders and receivers are treated together.
niklase@google.com470e71d2011-07-07 08:21:25 +0000383
danilchap162abd32015-12-10 02:39:40 -0800384 reconsideration NOT required for peer-to-peer
385 "timer reconsideration" is
386 employed. This algorithm implements a simple back-off mechanism
387 which causes users to hold back RTCP packet transmission if the
388 group sizes are increasing.
niklase@google.com470e71d2011-07-07 08:21:25 +0000389
danilchap162abd32015-12-10 02:39:40 -0800390 n = number of members
391 C = avg_size/(rtcpBW/4)
niklase@google.com470e71d2011-07-07 08:21:25 +0000392
danilchap162abd32015-12-10 02:39:40 -0800393 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
niklase@google.com470e71d2011-07-07 08:21:25 +0000394
danilchap162abd32015-12-10 02:39:40 -0800395 4. The calculated interval T is set to a number uniformly distributed
396 between 0.5 and 1.5 times the deterministic calculated interval.
niklase@google.com470e71d2011-07-07 08:21:25 +0000397
danilchap162abd32015-12-10 02:39:40 -0800398 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
399 for the fact that the timer reconsideration algorithm converges to
400 a value of the RTCP bandwidth below the intended average
401 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000402
Erik Språng242e22b2015-05-11 10:17:43 +0200403 int64_t now = clock_->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000404
Erik Språng242e22b2015-05-11 10:17:43 +0200405 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
xians@webrtc.org8738d272011-11-25 13:43:53 +0000406
pbosda903ea2015-10-02 02:36:56 -0700407 if (method_ == RtcpMode::kOff)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000409
Erik Språng242e22b2015-05-11 10:17:43 +0200410 if (!audio_ && sendKeyframeBeforeRTP) {
Erik Språng61be2a42015-04-27 13:32:52 +0200411 // for video key-frames we want to send the RTCP before the large key-frame
412 // if we have a 100 ms margin
413 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
414 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
Erik Språng242e22b2015-05-11 10:17:43 +0200416 if (now >= next_time_to_send_rtcp_) {
Erik Språng61be2a42015-04-27 13:32:52 +0200417 return true;
418 } else if (now < 0x0000ffff &&
Erik Språng242e22b2015-05-11 10:17:43 +0200419 next_time_to_send_rtcp_ > 0xffff0000) { // 65 sec margin
Erik Språng61be2a42015-04-27 13:32:52 +0200420 // wrap
421 return true;
422 }
423 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000424}
425
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000426int64_t RTCPSender::SendTimeOfSendReport(uint32_t sendReport) {
Erik Språng242e22b2015-05-11 10:17:43 +0200427 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000428
Erik Språng61be2a42015-04-27 13:32:52 +0200429 // This is only saved when we are the sender
Erik Språng242e22b2015-05-11 10:17:43 +0200430 if ((last_send_report_[0] == 0) || (sendReport == 0)) {
Erik Språng61be2a42015-04-27 13:32:52 +0200431 return 0; // will be ignored
432 } else {
433 for (int i = 0; i < RTCP_NUMBER_OF_SR; ++i) {
Erik Språng242e22b2015-05-11 10:17:43 +0200434 if (last_send_report_[i] == sendReport)
435 return last_rtcp_time_[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000436 }
Erik Språng61be2a42015-04-27 13:32:52 +0200437 }
438 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000439}
440
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000441bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
442 int64_t* time_ms) const {
Erik Språng242e22b2015-05-11 10:17:43 +0200443 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000444
445 if (last_xr_rr_.empty()) {
446 return false;
447 }
448 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
449 if (it == last_xr_rr_.end()) {
450 return false;
451 }
452 *time_ms = it->second;
453 return true;
454}
455
Erik Språngf7c57762015-12-04 10:40:35 +0100456rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSR(const RtcpContext& ctx) {
Erik Språng61be2a42015-04-27 13:32:52 +0200457 for (int i = (RTCP_NUMBER_OF_SR - 2); i >= 0; i--) {
458 // shift old
Erik Språng242e22b2015-05-11 10:17:43 +0200459 last_send_report_[i + 1] = last_send_report_[i];
460 last_rtcp_time_[i + 1] = last_rtcp_time_[i];
Erik Språng61be2a42015-04-27 13:32:52 +0200461 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000462
Erik Språngf7c57762015-12-04 10:40:35 +0100463 last_rtcp_time_[0] = Clock::NtpToMs(ctx.ntp_sec_, ctx.ntp_frac_);
464 last_send_report_[0] = (ctx.ntp_sec_ << 16) + (ctx.ntp_frac_ >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000465
Erik Språng61be2a42015-04-27 13:32:52 +0200466 // The timestamp of this RTCP packet should be estimated as the timestamp of
467 // the frame being captured at this moment. We are calculating that
468 // timestamp as the last frame's timestamp + the time since the last frame
469 // was captured.
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200470 uint32_t rtp_timestamp =
471 start_timestamp_ + last_rtp_timestamp_ +
472 (clock_->TimeInMilliseconds() - last_frame_capture_time_ms_) *
Erik Språngf7c57762015-12-04 10:40:35 +0100473 (ctx.feedback_state_.frequency_hz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000474
Erik Språngf7c57762015-12-04 10:40:35 +0100475 rtcp::SenderReport* report = new rtcp::SenderReport();
476 report->From(ssrc_);
477 report->WithNtpSec(ctx.ntp_sec_);
478 report->WithNtpFrac(ctx.ntp_frac_);
479 report->WithRtpTimestamp(rtp_timestamp);
480 report->WithPacketCount(ctx.feedback_state_.packets_sent);
481 report->WithOctetCount(ctx.feedback_state_.media_bytes_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000482
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200483 for (auto it : report_blocks_)
Erik Språngf7c57762015-12-04 10:40:35 +0100484 report->WithReportBlock(it.second);
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200486 report_blocks_.clear();
Erik Språngf7c57762015-12-04 10:40:35 +0100487
488 return rtc::scoped_ptr<rtcp::SenderReport>(report);
niklase@google.com470e71d2011-07-07 08:21:25 +0000489}
490
Erik Språngf7c57762015-12-04 10:40:35 +0100491rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSDES(
492 const RtcpContext& ctx) {
Erik Språng0ea42d32015-06-25 14:46:16 +0200493 size_t length_cname = cname_.length();
henrikg91d6ede2015-09-17 00:24:34 -0700494 RTC_CHECK_LT(length_cname, static_cast<size_t>(RTCP_CNAME_SIZE));
niklase@google.com470e71d2011-07-07 08:21:25 +0000495
Erik Språngf7c57762015-12-04 10:40:35 +0100496 rtcp::Sdes* sdes = new rtcp::Sdes();
497 sdes->WithCName(ssrc_, cname_);
Erik Språng0ea42d32015-06-25 14:46:16 +0200498
499 for (const auto it : csrc_cnames_)
Erik Språngf7c57762015-12-04 10:40:35 +0100500 sdes->WithCName(it.first, it.second);
Erik Språng0ea42d32015-06-25 14:46:16 +0200501
Erik Språngf7c57762015-12-04 10:40:35 +0100502 return rtc::scoped_ptr<rtcp::Sdes>(sdes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000503}
504
Erik Språngf7c57762015-12-04 10:40:35 +0100505rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildRR(const RtcpContext& ctx) {
506 rtcp::ReceiverReport* report = new rtcp::ReceiverReport();
507 report->From(ssrc_);
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200508 for (auto it : report_blocks_)
Erik Språngf7c57762015-12-04 10:40:35 +0100509 report->WithReportBlock(it.second);
Erik Språng61be2a42015-04-27 13:32:52 +0200510
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200511 report_blocks_.clear();
Erik Språngf7c57762015-12-04 10:40:35 +0100512 return rtc::scoped_ptr<rtcp::ReceiverReport>(report);
niklase@google.com470e71d2011-07-07 08:21:25 +0000513}
514
Erik Språngf7c57762015-12-04 10:40:35 +0100515rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildPLI(const RtcpContext& ctx) {
516 rtcp::Pli* pli = new rtcp::Pli();
517 pli->From(ssrc_);
518 pli->To(remote_ssrc_);
Erik Språng61be2a42015-04-27 13:32:52 +0200519
Erik Språng242e22b2015-05-11 10:17:43 +0200520 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
521 "RTCPSender::PLI");
522 ++packet_type_counter_.pli_packets;
523 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_PLICount",
524 ssrc_, packet_type_counter_.pli_packets);
525
Erik Språngf7c57762015-12-04 10:40:35 +0100526 return rtc::scoped_ptr<rtcp::Pli>(pli);
Erik Språng61be2a42015-04-27 13:32:52 +0200527}
528
Erik Språngf7c57762015-12-04 10:40:35 +0100529rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildFIR(const RtcpContext& ctx) {
530 if (!ctx.repeat_)
sprang62dae192015-08-05 02:35:35 -0700531 ++sequence_number_fir_; // Do not increase if repetition.
niklase@google.com470e71d2011-07-07 08:21:25 +0000532
Erik Språngf7c57762015-12-04 10:40:35 +0100533 rtcp::Fir* fir = new rtcp::Fir();
534 fir->From(ssrc_);
535 fir->To(remote_ssrc_);
536 fir->WithCommandSeqNum(sequence_number_fir_);
Erik Språng242e22b2015-05-11 10:17:43 +0200537
538 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
539 "RTCPSender::FIR");
540 ++packet_type_counter_.fir_packets;
541 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_FIRCount",
542 ssrc_, packet_type_counter_.fir_packets);
543
Erik Språngf7c57762015-12-04 10:40:35 +0100544 return rtc::scoped_ptr<rtcp::Fir>(fir);
niklase@google.com470e71d2011-07-07 08:21:25 +0000545}
546
547/*
548 0 1 2 3
549 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
550 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
551 | First | Number | PictureID |
552 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
553*/
Erik Språngf7c57762015-12-04 10:40:35 +0100554rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSLI(const RtcpContext& ctx) {
555 rtcp::Sli* sli = new rtcp::Sli();
556 sli->From(ssrc_);
557 sli->To(remote_ssrc_);
sprang0365a272015-08-11 01:02:37 -0700558 // Crop picture id to 6 least significant bits.
Erik Språngf7c57762015-12-04 10:40:35 +0100559 sli->WithPictureId(ctx.picture_id_ & 0x3F);
560 sli->WithFirstMb(0);
561 sli->WithNumberOfMb(0x1FFF); // 13 bits, only ones for now.
sprang0365a272015-08-11 01:02:37 -0700562
Erik Språngf7c57762015-12-04 10:40:35 +0100563 return rtc::scoped_ptr<rtcp::Sli>(sli);
niklase@google.com470e71d2011-07-07 08:21:25 +0000564}
565
566/*
567 0 1 2 3
568 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
569 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 | PB |0| Payload Type| Native RPSI bit string |
571 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
572 | defined per codec ... | Padding (0) |
573 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574*/
575/*
576* Note: not generic made for VP8
577*/
Erik Språngf7c57762015-12-04 10:40:35 +0100578rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildRPSI(
579 const RtcpContext& ctx) {
580 if (ctx.feedback_state_.send_payload_type == 0xFF)
581 return nullptr;
Erik Språng242e22b2015-05-11 10:17:43 +0200582
Erik Språngf7c57762015-12-04 10:40:35 +0100583 rtcp::Rpsi* rpsi = new rtcp::Rpsi();
584 rpsi->From(ssrc_);
585 rpsi->To(remote_ssrc_);
586 rpsi->WithPayloadType(ctx.feedback_state_.send_payload_type);
587 rpsi->WithPictureId(ctx.picture_id_);
sprangcf7f54d2015-08-13 04:37:42 -0700588
Erik Språngf7c57762015-12-04 10:40:35 +0100589 return rtc::scoped_ptr<rtcp::Rpsi>(rpsi);
niklase@google.com470e71d2011-07-07 08:21:25 +0000590}
591
Erik Språngf7c57762015-12-04 10:40:35 +0100592rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildREMB(
593 const RtcpContext& ctx) {
594 rtcp::Remb* remb = new rtcp::Remb();
595 remb->From(ssrc_);
sprangdd4edc52015-08-21 04:21:51 -0700596 for (uint32_t ssrc : remb_ssrcs_)
Erik Språngf7c57762015-12-04 10:40:35 +0100597 remb->AppliesTo(ssrc);
598 remb->WithBitrateBps(remb_bitrate_);
Erik Språng61be2a42015-04-27 13:32:52 +0200599
Erik Språng242e22b2015-05-11 10:17:43 +0200600 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
601 "RTCPSender::REMB");
602
Erik Språngf7c57762015-12-04 10:40:35 +0100603 return rtc::scoped_ptr<rtcp::Remb>(remb);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000604}
605
Erik Språng61be2a42015-04-27 13:32:52 +0200606void RTCPSender::SetTargetBitrate(unsigned int target_bitrate) {
Erik Språng242e22b2015-05-11 10:17:43 +0200607 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
608 tmmbr_send_ = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +0000609}
610
Erik Språngf7c57762015-12-04 10:40:35 +0100611rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBR(
612 const RtcpContext& ctx) {
613 if (ctx.feedback_state_.module == nullptr)
614 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200615 // Before sending the TMMBR check the received TMMBN, only an owner is
616 // allowed to raise the bitrate:
617 // * If the sender is an owner of the TMMBN -> send TMMBR
618 // * If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
niklase@google.com470e71d2011-07-07 08:21:25 +0000619
Erik Språng61be2a42015-04-27 13:32:52 +0200620 // get current bounding set from RTCP receiver
621 bool tmmbrOwner = false;
622 // store in candidateSet, allocates one extra slot
Erik Språng242e22b2015-05-11 10:17:43 +0200623 TMMBRSet* candidateSet = tmmbr_help_.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000624
Erik Språng242e22b2015-05-11 10:17:43 +0200625 // holding critical_section_rtcp_sender_ while calling RTCPreceiver which
626 // will accuire criticalSectionRTCPReceiver_ is a potental deadlock but
Erik Språng61be2a42015-04-27 13:32:52 +0200627 // since RTCPreceiver is not doing the reverse we should be fine
628 int32_t lengthOfBoundingSet =
danilchap6db6cdc2015-12-15 02:54:47 -0800629 ctx.feedback_state_.module->BoundingSet(&tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +0000630
Erik Språng61be2a42015-04-27 13:32:52 +0200631 if (lengthOfBoundingSet > 0) {
632 for (int32_t i = 0; i < lengthOfBoundingSet; i++) {
Erik Språng242e22b2015-05-11 10:17:43 +0200633 if (candidateSet->Tmmbr(i) == tmmbr_send_ &&
634 candidateSet->PacketOH(i) == packet_oh_send_) {
Erik Språngf7c57762015-12-04 10:40:35 +0100635 // Do not send the same tuple.
636 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200637 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 }
Erik Språng61be2a42015-04-27 13:32:52 +0200639 if (!tmmbrOwner) {
640 // use received bounding set as candidate set
641 // add current tuple
Erik Språng242e22b2015-05-11 10:17:43 +0200642 candidateSet->SetEntry(lengthOfBoundingSet, tmmbr_send_, packet_oh_send_,
643 ssrc_);
Erik Språng61be2a42015-04-27 13:32:52 +0200644 int numCandidates = lengthOfBoundingSet + 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000645
Erik Språng61be2a42015-04-27 13:32:52 +0200646 // find bounding set
Erik Språngf7c57762015-12-04 10:40:35 +0100647 TMMBRSet* boundingSet = nullptr;
Erik Språng242e22b2015-05-11 10:17:43 +0200648 int numBoundingSet = tmmbr_help_.FindTMMBRBoundingSet(boundingSet);
Erik Språng61be2a42015-04-27 13:32:52 +0200649 if (numBoundingSet > 0 || numBoundingSet <= numCandidates)
Erik Språng242e22b2015-05-11 10:17:43 +0200650 tmmbrOwner = tmmbr_help_.IsOwner(ssrc_, numBoundingSet);
Erik Språng61be2a42015-04-27 13:32:52 +0200651 if (!tmmbrOwner) {
Erik Språngf7c57762015-12-04 10:40:35 +0100652 // Did not enter bounding set, no meaning to send this request.
653 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200654 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 }
Erik Språng61be2a42015-04-27 13:32:52 +0200656 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000657
Erik Språngf7c57762015-12-04 10:40:35 +0100658 if (!tmmbr_send_)
659 return nullptr;
sprang81a3e602015-08-21 05:30:11 -0700660
Erik Språngf7c57762015-12-04 10:40:35 +0100661 rtcp::Tmmbr* tmmbr = new rtcp::Tmmbr();
662 tmmbr->From(ssrc_);
663 tmmbr->To(remote_ssrc_);
664 tmmbr->WithBitrateKbps(tmmbr_send_);
665 tmmbr->WithOverhead(packet_oh_send_);
666
667 return rtc::scoped_ptr<rtcp::Tmmbr>(tmmbr);
Erik Språng61be2a42015-04-27 13:32:52 +0200668}
669
Erik Språngf7c57762015-12-04 10:40:35 +0100670rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBN(
671 const RtcpContext& ctx) {
Erik Språng242e22b2015-05-11 10:17:43 +0200672 TMMBRSet* boundingSet = tmmbr_help_.BoundingSetToSend();
Erik Språngf7c57762015-12-04 10:40:35 +0100673 if (boundingSet == nullptr)
674 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200675
Erik Språngf7c57762015-12-04 10:40:35 +0100676 rtcp::Tmmbn* tmmbn = new rtcp::Tmmbn();
677 tmmbn->From(ssrc_);
sprangd83df502015-08-27 01:05:08 -0700678 for (uint32_t i = 0; i < boundingSet->lengthOfSet(); i++) {
679 if (boundingSet->Tmmbr(i) > 0) {
Erik Språngf7c57762015-12-04 10:40:35 +0100680 tmmbn->WithTmmbr(boundingSet->Ssrc(i), boundingSet->Tmmbr(i),
681 boundingSet->PacketOH(i));
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +0000682 }
Erik Språng61be2a42015-04-27 13:32:52 +0200683 }
sprangd83df502015-08-27 01:05:08 -0700684
Erik Språngf7c57762015-12-04 10:40:35 +0100685 return rtc::scoped_ptr<rtcp::Tmmbn>(tmmbn);
niklase@google.com470e71d2011-07-07 08:21:25 +0000686}
687
Erik Språngf7c57762015-12-04 10:40:35 +0100688rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildAPP(const RtcpContext& ctx) {
689 rtcp::App* app = new rtcp::App();
690 app->From(ssrc_);
691 app->WithSubType(app_sub_type_);
692 app->WithName(app_name_);
693 app->WithData(app_data_.get(), app_length_);
Erik Språng521875a2015-09-01 10:11:16 +0200694
Erik Språngf7c57762015-12-04 10:40:35 +0100695 return rtc::scoped_ptr<rtcp::App>(app);
Erik Språng61be2a42015-04-27 13:32:52 +0200696}
697
Erik Språngf7c57762015-12-04 10:40:35 +0100698rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK(
699 const RtcpContext& ctx) {
700 rtcp::Nack* nack = new rtcp::Nack();
701 nack->From(ssrc_);
702 nack->To(remote_ssrc_);
703 nack->WithList(ctx.nack_list_, ctx.nack_size_);
Erik Språng61be2a42015-04-27 13:32:52 +0200704
705 // Report stats.
706 NACKStringBuilder stringBuilder;
Erik Språngf7c57762015-12-04 10:40:35 +0100707 for (int idx = 0; idx < ctx.nack_size_; ++idx) {
708 stringBuilder.PushNACK(ctx.nack_list_[idx]);
709 nack_stats_.ReportRequest(ctx.nack_list_[idx]);
Erik Språng61be2a42015-04-27 13:32:52 +0200710 }
Erik Språng61be2a42015-04-27 13:32:52 +0200711 packet_type_counter_.nack_requests = nack_stats_.requests();
712 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
Erik Språng242e22b2015-05-11 10:17:43 +0200713
714 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
715 "RTCPSender::NACK", "nacks",
716 TRACE_STR_COPY(stringBuilder.GetResult().c_str()));
717 ++packet_type_counter_.nack_packets;
718 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_NACKCount",
719 ssrc_, packet_type_counter_.nack_packets);
720
Erik Språngf7c57762015-12-04 10:40:35 +0100721 return rtc::scoped_ptr<rtcp::Nack>(nack);
Erik Språng61be2a42015-04-27 13:32:52 +0200722}
723
Erik Språngf7c57762015-12-04 10:40:35 +0100724rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildBYE(const RtcpContext& ctx) {
725 rtcp::Bye* bye = new rtcp::Bye();
726 bye->From(ssrc_);
sprangd8ee4f92015-08-24 03:25:19 -0700727 for (uint32_t csrc : csrcs_)
Erik Språngf7c57762015-12-04 10:40:35 +0100728 bye->WithCsrc(csrc);
sprangd8ee4f92015-08-24 03:25:19 -0700729
Erik Språngf7c57762015-12-04 10:40:35 +0100730 return rtc::scoped_ptr<rtcp::Bye>(bye);
niklase@google.com470e71d2011-07-07 08:21:25 +0000731}
732
Erik Språngf7c57762015-12-04 10:40:35 +0100733rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildReceiverReferenceTime(
734 const RtcpContext& ctx) {
Erik Språng61be2a42015-04-27 13:32:52 +0200735 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000736 last_xr_rr_.erase(last_xr_rr_.begin());
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000737 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
Erik Språngf7c57762015-12-04 10:40:35 +0100738 RTCPUtility::MidNtp(ctx.ntp_sec_, ctx.ntp_frac_),
739 Clock::NtpToMs(ctx.ntp_sec_, ctx.ntp_frac_)));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000740
Erik Språngf7c57762015-12-04 10:40:35 +0100741 rtcp::Xr* xr = new rtcp::Xr();
742 xr->From(ssrc_);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000743
Erik Språngca28fdc2015-08-31 14:00:50 +0200744 rtcp::Rrtr rrtr;
Danil Chapovalovfc47ed62015-12-07 14:46:35 +0100745 rrtr.WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000746
Erik Språngf7c57762015-12-04 10:40:35 +0100747 xr->WithRrtr(&rrtr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000748
Erik Språngca28fdc2015-08-31 14:00:50 +0200749 // TODO(sprang): Merge XR report sending to contain all of RRTR, DLRR, VOIP?
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000750
Erik Språngf7c57762015-12-04 10:40:35 +0100751 return rtc::scoped_ptr<rtcp::Xr>(xr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000752}
753
Erik Språngf7c57762015-12-04 10:40:35 +0100754rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildDlrr(
755 const RtcpContext& ctx) {
756 rtcp::Xr* xr = new rtcp::Xr();
757 xr->From(ssrc_);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000758
Erik Språngca28fdc2015-08-31 14:00:50 +0200759 rtcp::Dlrr dlrr;
Erik Språngf7c57762015-12-04 10:40:35 +0100760 const RtcpReceiveTimeInfo& info = ctx.feedback_state_.last_xr_rr;
Erik Språngca28fdc2015-08-31 14:00:50 +0200761 dlrr.WithDlrrItem(info.sourceSSRC, info.lastRR, info.delaySinceLastRR);
762
Erik Språngf7c57762015-12-04 10:40:35 +0100763 xr->WithDlrr(&dlrr);
Erik Språngca28fdc2015-08-31 14:00:50 +0200764
Erik Språngf7c57762015-12-04 10:40:35 +0100765 return rtc::scoped_ptr<rtcp::Xr>(xr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000766}
767
Erik Språng242e22b2015-05-11 10:17:43 +0200768// TODO(sprang): Add a unit test for this, or remove if the code isn't used.
Erik Språngf7c57762015-12-04 10:40:35 +0100769rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildVoIPMetric(
770 const RtcpContext& context) {
771 rtcp::Xr* xr = new rtcp::Xr();
772 xr->From(ssrc_);
Erik Språngca28fdc2015-08-31 14:00:50 +0200773
774 rtcp::VoipMetric voip;
775 voip.To(remote_ssrc_);
danilchap91941ae2015-12-15 07:06:36 -0800776 voip.WithVoipMetric(xr_voip_metric_);
Erik Språngca28fdc2015-08-31 14:00:50 +0200777
Erik Språngf7c57762015-12-04 10:40:35 +0100778 xr->WithVoipMetric(&voip);
Erik Språngca28fdc2015-08-31 14:00:50 +0200779
Erik Språngf7c57762015-12-04 10:40:35 +0100780 return rtc::scoped_ptr<rtcp::Xr>(xr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000781}
782
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000783int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
Erik Språng242e22b2015-05-11 10:17:43 +0200784 RTCPPacketType packetType,
785 int32_t nack_size,
786 const uint16_t* nack_list,
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000787 bool repeat,
788 uint64_t pictureID) {
Erik Språng242e22b2015-05-11 10:17:43 +0200789 return SendCompoundRTCP(
790 feedback_state, std::set<RTCPPacketType>(&packetType, &packetType + 1),
791 nack_size, nack_list, repeat, pictureID);
792}
793
794int32_t RTCPSender::SendCompoundRTCP(
795 const FeedbackState& feedback_state,
Erik Språngf7c57762015-12-04 10:40:35 +0100796 const std::set<RTCPPacketType>& packet_types,
Erik Språng242e22b2015-05-11 10:17:43 +0200797 int32_t nack_size,
798 const uint16_t* nack_list,
799 bool repeat,
800 uint64_t pictureID) {
Erik Språngf7c57762015-12-04 10:40:35 +0100801 PacketContainer container(transport_);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000802 {
Erik Språng242e22b2015-05-11 10:17:43 +0200803 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
pbosda903ea2015-10-02 02:36:56 -0700804 if (method_ == RtcpMode::kOff) {
Erik Språng61be2a42015-04-27 13:32:52 +0200805 LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
806 return -1;
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +0000807 }
Erik Språngf7c57762015-12-04 10:40:35 +0100808
809 // We need to send our NTP even if we haven't received any reports.
810 uint32_t ntp_sec;
811 uint32_t ntp_frac;
812 clock_->CurrentNtp(ntp_sec, ntp_frac);
813 RtcpContext context(feedback_state, nack_size, nack_list, repeat, pictureID,
814 ntp_sec, ntp_frac, &container);
815
816 PrepareReport(packet_types, feedback_state);
817
818 auto it = report_flags_.begin();
819 while (it != report_flags_.end()) {
820 auto builder_it = builders_.find(it->type);
821 RTC_DCHECK(builder_it != builders_.end());
822 if (it->is_volatile) {
823 report_flags_.erase(it++);
824 } else {
825 ++it;
826 }
827
828 BuilderFunc func = builder_it->second;
829 rtc::scoped_ptr<rtcp::RtcpPacket> packet = (this->*func)(context);
830 if (packet.get() == nullptr)
831 return -1;
832 container.Append(packet.release());
833 }
834
835 if (packet_type_counter_observer_ != nullptr) {
836 packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
837 remote_ssrc_, packet_type_counter_);
838 }
839
840 RTC_DCHECK(AllVolatileFlagsConsumed());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000841 }
Erik Språng61be2a42015-04-27 13:32:52 +0200842
Erik Språngf7c57762015-12-04 10:40:35 +0100843 size_t bytes_sent = container.SendPackets();
844 return bytes_sent == 0 ? -1 : 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000845}
846
Erik Språngf7c57762015-12-04 10:40:35 +0100847void RTCPSender::PrepareReport(const std::set<RTCPPacketType>& packetTypes,
848 const FeedbackState& feedback_state) {
Erik Språng242e22b2015-05-11 10:17:43 +0200849 // Add all flags as volatile. Non volatile entries will not be overwritten
850 // and all new volatile flags added will be consumed by the end of this call.
851 SetFlags(packetTypes, true);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000852
Erik Språng61be2a42015-04-27 13:32:52 +0200853 if (packet_type_counter_.first_packet_time_ms == -1)
Erik Språng242e22b2015-05-11 10:17:43 +0200854 packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds();
Erik Språng61be2a42015-04-27 13:32:52 +0200855
Erik Språng242e22b2015-05-11 10:17:43 +0200856 bool generate_report;
857 if (IsFlagPresent(kRtcpSr) || IsFlagPresent(kRtcpRr)) {
858 // Report type already explicitly set, don't automatically populate.
859 generate_report = true;
henrikg91d6ede2015-09-17 00:24:34 -0700860 RTC_DCHECK(ConsumeFlag(kRtcpReport) == false);
Erik Språng242e22b2015-05-11 10:17:43 +0200861 } else {
862 generate_report =
pbosda903ea2015-10-02 02:36:56 -0700863 (ConsumeFlag(kRtcpReport) && method_ == RtcpMode::kReducedSize) ||
864 method_ == RtcpMode::kCompound;
Erik Språng242e22b2015-05-11 10:17:43 +0200865 if (generate_report)
866 SetFlag(sending_ ? kRtcpSr : kRtcpRr, true);
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000867 }
868
Erik Språng0ea42d32015-06-25 14:46:16 +0200869 if (IsFlagPresent(kRtcpSr) || (IsFlagPresent(kRtcpRr) && !cname_.empty()))
Erik Språng242e22b2015-05-11 10:17:43 +0200870 SetFlag(kRtcpSdes, true);
871
Erik Språng242e22b2015-05-11 10:17:43 +0200872 if (generate_report) {
873 if (!sending_ && xr_send_receiver_reference_time_enabled_)
874 SetFlag(kRtcpXrReceiverReferenceTime, true);
Erik Språng61be2a42015-04-27 13:32:52 +0200875 if (feedback_state.has_last_xr_rr)
Erik Språng242e22b2015-05-11 10:17:43 +0200876 SetFlag(kRtcpXrDlrrReportBlock, true);
877
878 // generate next time to send an RTCP report
danilchap47a740b2015-12-15 00:30:07 -0800879 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000880
danilchap47a740b2015-12-15 00:30:07 -0800881 if (!audio_) {
Erik Språng242e22b2015-05-11 10:17:43 +0200882 if (sending_) {
Erik Språng61be2a42015-04-27 13:32:52 +0200883 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
884 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
885 if (send_bitrate_kbit != 0)
886 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000887 }
Erik Språng61be2a42015-04-27 13:32:52 +0200888 if (minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
889 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
Erik Språng61be2a42015-04-27 13:32:52 +0200890 }
danilchap47a740b2015-12-15 00:30:07 -0800891 // The interval between RTCP packets is varied randomly over the
892 // range [1/2,3/2] times the calculated interval.
893 uint32_t timeToNext =
894 random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2);
Erik Språng242e22b2015-05-11 10:17:43 +0200895 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000896
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000897 StatisticianMap statisticians =
898 receive_statistics_->GetActiveStatisticians();
danilchapa72e7342015-12-22 08:07:45 -0800899 RTC_DCHECK(report_blocks_.empty());
900 for (auto& it : statisticians) {
901 AddReportBlock(feedback_state, it.first, it.second);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000902 }
903 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000904}
905
danilchapa72e7342015-12-22 08:07:45 -0800906bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state,
907 uint32_t ssrc,
908 StreamStatistician* statistician) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000909 // Do we have receive statistics to send?
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000910 RtcpStatistics stats;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000911 if (!statistician->GetStatistics(&stats, true))
912 return false;
danilchapa72e7342015-12-22 08:07:45 -0800913
914 if (report_blocks_.size() >= RTCP_MAX_REPORT_BLOCKS) {
915 LOG(LS_WARNING) << "Too many report blocks.";
916 return false;
917 }
918 RTC_DCHECK(report_blocks_.find(ssrc) == report_blocks_.end());
919 rtcp::ReportBlock* block = &report_blocks_[ssrc];
920 block->To(ssrc);
921 block->WithFractionLost(stats.fraction_lost);
922 if (!block->WithCumulativeLost(stats.cumulative_lost)) {
923 report_blocks_.erase(ssrc);
924 LOG(LS_WARNING) << "Cumulative lost is oversized.";
925 return false;
926 }
927 block->WithExtHighestSeqNum(stats.extended_max_sequence_number);
928 block->WithJitter(stats.jitter);
929 block->WithLastSr(feedback_state.remote_sr);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000930
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200931 // TODO(sprang): Do we really need separate time stamps for each report?
932 // Get our NTP as late as possible to avoid a race.
933 uint32_t ntp_secs;
934 uint32_t ntp_frac;
935 clock_->CurrentNtp(ntp_secs, ntp_frac);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000936
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200937 // Delay since last received report.
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000938 if ((feedback_state.last_rr_ntp_secs != 0) ||
939 (feedback_state.last_rr_ntp_frac != 0)) {
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200940 // Get the 16 lowest bits of seconds and the 16 highest bits of fractions.
941 uint32_t now = ntp_secs & 0x0000FFFF;
Erik Språng61be2a42015-04-27 13:32:52 +0200942 now <<= 16;
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200943 now += (ntp_frac & 0xffff0000) >> 16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000944
Erik Språng61be2a42015-04-27 13:32:52 +0200945 uint32_t receiveTime = feedback_state.last_rr_ntp_secs & 0x0000FFFF;
946 receiveTime <<= 16;
947 receiveTime += (feedback_state.last_rr_ntp_frac & 0xffff0000) >> 16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000948
danilchapa72e7342015-12-22 08:07:45 -0800949 block->WithDelayLastSr(now - receiveTime);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000950 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000951 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000952}
953
pbos@webrtc.org9334ac22014-11-24 08:25:50 +0000954void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
955 assert(csrcs.size() <= kRtpCsrcSize);
Erik Språng242e22b2015-05-11 10:17:43 +0200956 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
pbos@webrtc.org9334ac22014-11-24 08:25:50 +0000957 csrcs_ = csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000958}
959
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000960int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
961 uint32_t name,
962 const uint8_t* data,
963 uint16_t length) {
Erik Språng61be2a42015-04-27 13:32:52 +0200964 if (length % 4 != 0) {
965 LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
966 return -1;
967 }
Erik Språng242e22b2015-05-11 10:17:43 +0200968 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000969
Erik Språng242e22b2015-05-11 10:17:43 +0200970 SetFlag(kRtcpApp, true);
971 app_sub_type_ = subType;
972 app_name_ = name;
973 app_data_.reset(new uint8_t[length]);
974 app_length_ = length;
975 memcpy(app_data_.get(), data, length);
Erik Språng61be2a42015-04-27 13:32:52 +0200976 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000977}
978
Erik Språng61be2a42015-04-27 13:32:52 +0200979int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
Erik Språng242e22b2015-05-11 10:17:43 +0200980 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
981 memcpy(&xr_voip_metric_, VoIPMetric, sizeof(RTCPVoIPMetric));
niklase@google.com470e71d2011-07-07 08:21:25 +0000982
Erik Språng242e22b2015-05-11 10:17:43 +0200983 SetFlag(kRtcpXrVoipMetric, true);
Erik Språng61be2a42015-04-27 13:32:52 +0200984 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000985}
986
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000987void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200988 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
989 xr_send_receiver_reference_time_enabled_ = enable;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000990}
991
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +0000992bool RTCPSender::RtcpXrReceiverReferenceTime() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200993 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
994 return xr_send_receiver_reference_time_enabled_;
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +0000995}
996
niklase@google.com470e71d2011-07-07 08:21:25 +0000997// no callbacks allowed inside this function
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000998int32_t RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
999 uint32_t maxBitrateKbit) {
Erik Språng242e22b2015-05-11 10:17:43 +02001000 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001001
Erik Språng242e22b2015-05-11 10:17:43 +02001002 if (0 == tmmbr_help_.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit)) {
1003 SetFlag(kRtcpTmmbn, true);
Erik Språng61be2a42015-04-27 13:32:52 +02001004 return 0;
1005 }
1006 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001007}
Erik Språng61be2a42015-04-27 13:32:52 +02001008
Erik Språng242e22b2015-05-11 10:17:43 +02001009void RTCPSender::SetFlag(RTCPPacketType type, bool is_volatile) {
1010 report_flags_.insert(ReportFlag(type, is_volatile));
1011}
1012
1013void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
1014 bool is_volatile) {
1015 for (RTCPPacketType type : types)
1016 SetFlag(type, is_volatile);
1017}
1018
1019bool RTCPSender::IsFlagPresent(RTCPPacketType type) const {
1020 return report_flags_.find(ReportFlag(type, false)) != report_flags_.end();
1021}
1022
1023bool RTCPSender::ConsumeFlag(RTCPPacketType type, bool forced) {
1024 auto it = report_flags_.find(ReportFlag(type, false));
1025 if (it == report_flags_.end())
1026 return false;
1027 if (it->is_volatile || forced)
1028 report_flags_.erase((it));
1029 return true;
1030}
1031
1032bool RTCPSender::AllVolatileFlagsConsumed() const {
1033 for (const ReportFlag& flag : report_flags_) {
1034 if (flag.is_volatile)
1035 return false;
1036 }
1037 return true;
1038}
1039
sprang233bd872015-09-08 13:25:16 -07001040bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
sprang233bd872015-09-08 13:25:16 -07001041 class Sender : public rtcp::RtcpPacket::PacketReadyCallback {
1042 public:
danilchap6db6cdc2015-12-15 02:54:47 -08001043 explicit Sender(Transport* transport)
Peter Boströmac547a62015-09-17 23:03:57 +02001044 : transport_(transport), send_failure_(false) {}
sprang233bd872015-09-08 13:25:16 -07001045
1046 void OnPacketReady(uint8_t* data, size_t length) override {
pbos2d566682015-09-28 09:59:31 -07001047 if (!transport_->SendRtcp(data, length))
sprang233bd872015-09-08 13:25:16 -07001048 send_failure_ = true;
1049 }
1050
1051 Transport* const transport_;
sprang233bd872015-09-08 13:25:16 -07001052 bool send_failure_;
sprang86fd9ed2015-09-29 04:45:43 -07001053 } sender(transport_);
sprang233bd872015-09-08 13:25:16 -07001054
1055 uint8_t buffer[IP_PACKET_SIZE];
1056 return packet.BuildExternalBuffer(buffer, IP_PACKET_SIZE, &sender) &&
1057 !sender.send_failure_;
1058}
1059
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001060} // namespace webrtc