blob: 64331a5e52bf754f16b38e8ce438fa3a81f50f42 [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"
danilchap2f7dea12016-01-13 02:03:04 -080027#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
Danil Chapovalov256e5b22016-01-15 14:16:24 +010028#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
Danil Chapovalov5679da12016-01-15 13:19:53 +010029#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/fir.h"
danilchapa8890a52015-12-22 03:43:04 -080030#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/nack.h"
danilchapf8385ad2015-11-27 05:36:09 -080031#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/pli.h"
Danil Chapovalov97f7e132015-12-04 16:13:30 +010032#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010033#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h"
Danil Chapovalov2c132972016-01-15 15:21:21 +010034#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/rpsi.h"
Danil Chapovalov1567d0b2016-01-15 17:34:27 +010035#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sdes.h"
danilchap92e677a2016-01-12 10:04:52 -080036#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sli.h"
danilchapef3d8052016-01-11 03:31:08 -080037#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.h"
danilchap7e8145f2016-01-11 11:49:19 -080038#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.h"
sprang233bd872015-09-08 13:25:16 -070039#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
tommie4f96502015-10-20 23:00:48 -070040#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010041#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
pwestin@webrtc.org741da942011-09-20 13:52:04 +000042
niklase@google.com470e71d2011-07-07 08:21:25 +000043namespace webrtc {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000044
45using RTCPUtility::RTCPCnameInformation;
46
Erik Språng61be2a42015-04-27 13:32:52 +020047NACKStringBuilder::NACKStringBuilder()
danilchap162abd32015-12-10 02:39:40 -080048 : stream_(""), count_(0), prevNack_(0), consecutive_(false) {}
edjee@google.com79b02892013-04-04 19:43:34 +000049
pbos@webrtc.orgf3e4cee2013-07-31 15:17:19 +000050NACKStringBuilder::~NACKStringBuilder() {}
51
danilchap162abd32015-12-10 02:39:40 -080052void NACKStringBuilder::PushNACK(uint16_t nack) {
Erik Språng242e22b2015-05-11 10:17:43 +020053 if (count_ == 0) {
54 stream_ << nack;
55 } else if (nack == prevNack_ + 1) {
56 consecutive_ = true;
Erik Språng61be2a42015-04-27 13:32:52 +020057 } else {
Erik Språng242e22b2015-05-11 10:17:43 +020058 if (consecutive_) {
59 stream_ << "-" << prevNack_;
60 consecutive_ = false;
edjee@google.com79b02892013-04-04 19:43:34 +000061 }
Erik Språng242e22b2015-05-11 10:17:43 +020062 stream_ << "," << nack;
Erik Språng61be2a42015-04-27 13:32:52 +020063 }
Erik Språng242e22b2015-05-11 10:17:43 +020064 count_++;
65 prevNack_ = nack;
edjee@google.com79b02892013-04-04 19:43:34 +000066}
67
Erik Språng61be2a42015-04-27 13:32:52 +020068std::string NACKStringBuilder::GetResult() {
Erik Språng242e22b2015-05-11 10:17:43 +020069 if (consecutive_) {
70 stream_ << "-" << prevNack_;
71 consecutive_ = false;
Erik Språng61be2a42015-04-27 13:32:52 +020072 }
Erik Språng242e22b2015-05-11 10:17:43 +020073 return stream_.str();
edjee@google.com79b02892013-04-04 19:43:34 +000074}
75
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000076RTCPSender::FeedbackState::FeedbackState()
77 : send_payload_type(0),
78 frequency_hz(0),
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +000079 packets_sent(0),
80 media_bytes_sent(0),
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000081 send_bitrate(0),
82 last_rr_ntp_secs(0),
83 last_rr_ntp_frac(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000084 remote_sr(0),
Erik Språng61be2a42015-04-27 13:32:52 +020085 has_last_xr_rr(false),
danilchap162abd32015-12-10 02:39:40 -080086 module(nullptr) {}
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000087
danilchap2f7dea12016-01-13 02:03:04 -080088class PacketContainer : public rtcp::CompoundPacket,
Erik Språngf7c57762015-12-04 10:40:35 +010089 public rtcp::RtcpPacket::PacketReadyCallback {
90 public:
91 explicit PacketContainer(Transport* transport)
92 : transport_(transport), bytes_sent_(0) {}
93 virtual ~PacketContainer() {
94 for (RtcpPacket* packet : appended_packets_)
95 delete packet;
96 }
97
98 void OnPacketReady(uint8_t* data, size_t length) override {
99 if (transport_->SendRtcp(data, length))
100 bytes_sent_ += length;
101 }
102
103 size_t SendPackets() {
danilchap2f7dea12016-01-13 02:03:04 -0800104 rtcp::CompoundPacket::Build(this);
Erik Språngf7c57762015-12-04 10:40:35 +0100105 return bytes_sent_;
106 }
107
108 private:
109 Transport* transport_;
110 size_t bytes_sent_;
111};
112
113class RTCPSender::RtcpContext {
114 public:
Erik Språng242e22b2015-05-11 10:17:43 +0200115 RtcpContext(const FeedbackState& feedback_state,
116 int32_t nack_size,
117 const uint16_t* nack_list,
118 bool repeat,
119 uint64_t picture_id,
Erik Språngf7c57762015-12-04 10:40:35 +0100120 uint32_t ntp_sec,
121 uint32_t ntp_frac,
122 PacketContainer* container)
123 : feedback_state_(feedback_state),
124 nack_size_(nack_size),
125 nack_list_(nack_list),
126 repeat_(repeat),
127 picture_id_(picture_id),
128 ntp_sec_(ntp_sec),
129 ntp_frac_(ntp_frac),
130 container_(container) {}
Erik Språng242e22b2015-05-11 10:17:43 +0200131
Erik Språngf7c57762015-12-04 10:40:35 +0100132 virtual ~RtcpContext() {}
Erik Språng242e22b2015-05-11 10:17:43 +0200133
Erik Språngf7c57762015-12-04 10:40:35 +0100134 const FeedbackState& feedback_state_;
135 const int32_t nack_size_;
136 const uint16_t* nack_list_;
137 const bool repeat_;
138 const uint64_t picture_id_;
139 const uint32_t ntp_sec_;
140 const uint32_t ntp_frac_;
Erik Språng242e22b2015-05-11 10:17:43 +0200141
Erik Språngf7c57762015-12-04 10:40:35 +0100142 PacketContainer* const container_;
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200143};
144
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000145RTCPSender::RTCPSender(
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000146 bool audio,
147 Clock* clock,
148 ReceiveStatistics* receive_statistics,
sprang86fd9ed2015-09-29 04:45:43 -0700149 RtcpPacketTypeCounterObserver* packet_type_counter_observer,
150 Transport* outgoing_transport)
Peter Boströmac547a62015-09-17 23:03:57 +0200151 : audio_(audio),
Erik Språng242e22b2015-05-11 10:17:43 +0200152 clock_(clock),
danilchap47a740b2015-12-15 00:30:07 -0800153 random_(clock_->TimeInMicroseconds()),
pbosda903ea2015-10-02 02:36:56 -0700154 method_(RtcpMode::kOff),
sprang86fd9ed2015-09-29 04:45:43 -0700155 transport_(outgoing_transport),
niklase@google.com470e71d2011-07-07 08:21:25 +0000156
Erik Språng242e22b2015-05-11 10:17:43 +0200157 critical_section_rtcp_sender_(
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000158 CriticalSectionWrapper::CreateCriticalSection()),
Erik Språng242e22b2015-05-11 10:17:43 +0200159 using_nack_(false),
160 sending_(false),
161 remb_enabled_(false),
Erik Språng242e22b2015-05-11 10:17:43 +0200162 next_time_to_send_rtcp_(0),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000163 start_timestamp_(0),
164 last_rtp_timestamp_(0),
165 last_frame_capture_time_ms_(-1),
Erik Språng242e22b2015-05-11 10:17:43 +0200166 ssrc_(0),
167 remote_ssrc_(0),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000168 receive_statistics_(receive_statistics),
niklase@google.com470e71d2011-07-07 08:21:25 +0000169
Erik Språng242e22b2015-05-11 10:17:43 +0200170 sequence_number_fir_(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000171
Erik Språng242e22b2015-05-11 10:17:43 +0200172 remb_bitrate_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000173
Erik Språng242e22b2015-05-11 10:17:43 +0200174 tmmbr_help_(),
175 tmmbr_send_(0),
176 packet_oh_send_(0),
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000177
Erik Språng242e22b2015-05-11 10:17:43 +0200178 app_sub_type_(0),
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200179 app_name_(0),
Erik Språng242e22b2015-05-11 10:17:43 +0200180 app_data_(nullptr),
181 app_length_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
Erik Språng242e22b2015-05-11 10:17:43 +0200183 xr_send_receiver_reference_time_enabled_(false),
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000184 packet_type_counter_observer_(packet_type_counter_observer) {
Erik Språng242e22b2015-05-11 10:17:43 +0200185 memset(last_send_report_, 0, sizeof(last_send_report_));
186 memset(last_rtcp_time_, 0, sizeof(last_rtcp_time_));
sprang86fd9ed2015-09-29 04:45:43 -0700187 RTC_DCHECK(transport_ != nullptr);
Erik Språng242e22b2015-05-11 10:17:43 +0200188
189 builders_[kRtcpSr] = &RTCPSender::BuildSR;
190 builders_[kRtcpRr] = &RTCPSender::BuildRR;
Erik Språng0ea42d32015-06-25 14:46:16 +0200191 builders_[kRtcpSdes] = &RTCPSender::BuildSDES;
Erik Språng242e22b2015-05-11 10:17:43 +0200192 builders_[kRtcpPli] = &RTCPSender::BuildPLI;
193 builders_[kRtcpFir] = &RTCPSender::BuildFIR;
194 builders_[kRtcpSli] = &RTCPSender::BuildSLI;
195 builders_[kRtcpRpsi] = &RTCPSender::BuildRPSI;
196 builders_[kRtcpRemb] = &RTCPSender::BuildREMB;
197 builders_[kRtcpBye] = &RTCPSender::BuildBYE;
198 builders_[kRtcpApp] = &RTCPSender::BuildAPP;
199 builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
200 builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
201 builders_[kRtcpNack] = &RTCPSender::BuildNACK;
202 builders_[kRtcpXrVoipMetric] = &RTCPSender::BuildVoIPMetric;
203 builders_[kRtcpXrReceiverReferenceTime] =
204 &RTCPSender::BuildReceiverReferenceTime;
205 builders_[kRtcpXrDlrrReportBlock] = &RTCPSender::BuildDlrr;
niklase@google.com470e71d2011-07-07 08:21:25 +0000206}
207
danilchap162abd32015-12-10 02:39:40 -0800208RTCPSender::~RTCPSender() {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
pbosda903ea2015-10-02 02:36:56 -0700210RtcpMode RTCPSender::Status() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200211 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
212 return method_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000213}
214
pbosda903ea2015-10-02 02:36:56 -0700215void RTCPSender::SetRTCPStatus(RtcpMode method) {
Erik Språng242e22b2015-05-11 10:17:43 +0200216 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
217 method_ = method;
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000218
pbosda903ea2015-10-02 02:36:56 -0700219 if (method == RtcpMode::kOff)
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000220 return;
Erik Språng242e22b2015-05-11 10:17:43 +0200221 next_time_to_send_rtcp_ =
222 clock_->TimeInMilliseconds() +
223 (audio_ ? RTCP_INTERVAL_AUDIO_MS / 2 : RTCP_INTERVAL_VIDEO_MS / 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000224}
225
Erik Språng61be2a42015-04-27 13:32:52 +0200226bool RTCPSender::Sending() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200227 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
228 return sending_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000229}
230
Erik Språng61be2a42015-04-27 13:32:52 +0200231int32_t RTCPSender::SetSendingStatus(const FeedbackState& feedback_state,
232 bool sending) {
233 bool sendRTCPBye = false;
234 {
Erik Språng242e22b2015-05-11 10:17:43 +0200235 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000236
pbosda903ea2015-10-02 02:36:56 -0700237 if (method_ != RtcpMode::kOff) {
Erik Språng242e22b2015-05-11 10:17:43 +0200238 if (sending == false && sending_ == true) {
Erik Språng61be2a42015-04-27 13:32:52 +0200239 // Trigger RTCP bye
240 sendRTCPBye = true;
241 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 }
Erik Språng242e22b2015-05-11 10:17:43 +0200243 sending_ = sending;
Erik Språng61be2a42015-04-27 13:32:52 +0200244 }
245 if (sendRTCPBye)
246 return SendRTCP(feedback_state, kRtcpBye);
247 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248}
249
Erik Språng61be2a42015-04-27 13:32:52 +0200250bool RTCPSender::REMB() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200251 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
252 return remb_enabled_;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000253}
254
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000255void RTCPSender::SetREMBStatus(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200256 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
257 remb_enabled_ = enable;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000258}
259
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000260void RTCPSender::SetREMBData(uint32_t bitrate,
261 const std::vector<uint32_t>& ssrcs) {
Erik Språng242e22b2015-05-11 10:17:43 +0200262 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
263 remb_bitrate_ = bitrate;
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000264 remb_ssrcs_ = ssrcs;
stefan@webrtc.org4ef438e2014-07-11 09:55:30 +0000265
Erik Språng242e22b2015-05-11 10:17:43 +0200266 if (remb_enabled_)
267 SetFlag(kRtcpRemb, false);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000268 // Send a REMB immediately if we have a new REMB. The frequency of REMBs is
269 // throttled by the caller.
Erik Språng242e22b2015-05-11 10:17:43 +0200270 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds();
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000271}
272
Erik Språng61be2a42015-04-27 13:32:52 +0200273bool RTCPSender::TMMBR() const {
Erik Språng242e22b2015-05-11 10:17:43 +0200274 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
275 return IsFlagPresent(RTCPPacketType::kRtcpTmmbr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000276}
277
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000278void RTCPSender::SetTMMBRStatus(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200279 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
280 if (enable) {
281 SetFlag(RTCPPacketType::kRtcpTmmbr, false);
282 } else {
283 ConsumeFlag(RTCPPacketType::kRtcpTmmbr, true);
284 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000287void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
Erik Språng242e22b2015-05-11 10:17:43 +0200288 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000289 start_timestamp_ = start_timestamp;
290}
291
292void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
293 int64_t capture_time_ms) {
Erik Språng242e22b2015-05-11 10:17:43 +0200294 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000295 last_rtp_timestamp_ = rtp_timestamp;
296 if (capture_time_ms < 0) {
297 // We don't currently get a capture time from VoiceEngine.
Erik Språng242e22b2015-05-11 10:17:43 +0200298 last_frame_capture_time_ms_ = clock_->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000299 } else {
300 last_frame_capture_time_ms_ = capture_time_ms;
301 }
302}
303
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000304void RTCPSender::SetSSRC(uint32_t ssrc) {
Erik Språng242e22b2015-05-11 10:17:43 +0200305 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000306
Erik Språng242e22b2015-05-11 10:17:43 +0200307 if (ssrc_ != 0) {
Erik Språng61be2a42015-04-27 13:32:52 +0200308 // not first SetSSRC, probably due to a collision
309 // schedule a new RTCP report
310 // make sure that we send a RTP packet
Erik Språng242e22b2015-05-11 10:17:43 +0200311 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + 100;
Erik Språng61be2a42015-04-27 13:32:52 +0200312 }
Erik Språng242e22b2015-05-11 10:17:43 +0200313 ssrc_ = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000314}
315
Erik Språng61be2a42015-04-27 13:32:52 +0200316void RTCPSender::SetRemoteSSRC(uint32_t ssrc) {
Erik Språng242e22b2015-05-11 10:17:43 +0200317 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
318 remote_ssrc_ = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000319}
320
Peter Boström9ba52f82015-06-01 14:12:28 +0200321int32_t RTCPSender::SetCNAME(const char* c_name) {
322 if (!c_name)
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000323 return -1;
324
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 cname_ = c_name;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000328 return 0;
329}
330
Erik Språng0ea42d32015-06-25 14:46:16 +0200331int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC, const char* c_name) {
332 assert(c_name);
henrikg91d6ede2015-09-17 00:24:34 -0700333 RTC_DCHECK_LT(strlen(c_name), static_cast<size_t>(RTCP_CNAME_SIZE));
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 if (csrc_cnames_.size() >= kRtpCsrcSize)
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000336 return -1;
Erik Språng0ea42d32015-06-25 14:46:16 +0200337
338 csrc_cnames_[SSRC] = c_name;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000339 return 0;
340}
341
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000342int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
Erik Språng242e22b2015-05-11 10:17:43 +0200343 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
Erik Språng0ea42d32015-06-25 14:46:16 +0200344 auto it = csrc_cnames_.find(SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000345
Erik Språng242e22b2015-05-11 10:17:43 +0200346 if (it == csrc_cnames_.end())
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000347 return -1;
Erik Språng61be2a42015-04-27 13:32:52 +0200348
Erik Språng242e22b2015-05-11 10:17:43 +0200349 csrc_cnames_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000350 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000351}
352
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000353bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
danilchap162abd32015-12-10 02:39:40 -0800354 /*
355 For audio we use a fix 5 sec interval
niklase@google.com470e71d2011-07-07 08:21:25 +0000356
danilchap162abd32015-12-10 02:39:40 -0800357 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
358 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but
359 that should be extremely rare
niklase@google.com470e71d2011-07-07 08:21:25 +0000360
361
danilchap162abd32015-12-10 02:39:40 -0800362 From RFC 3550
niklase@google.com470e71d2011-07-07 08:21:25 +0000363
danilchap162abd32015-12-10 02:39:40 -0800364 MAX RTCP BW is 5% if the session BW
365 A send report is approximately 65 bytes inc CNAME
366 A receiver report is approximately 28 bytes
niklase@google.com470e71d2011-07-07 08:21:25 +0000367
danilchap162abd32015-12-10 02:39:40 -0800368 The RECOMMENDED value for the reduced minimum in seconds is 360
369 divided by the session bandwidth in kilobits/second. This minimum
370 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
niklase@google.com470e71d2011-07-07 08:21:25 +0000371
danilchap162abd32015-12-10 02:39:40 -0800372 If the participant has not yet sent an RTCP packet (the variable
373 initial is true), the constant Tmin is set to 2.5 seconds, else it
374 is set to 5 seconds.
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
danilchap162abd32015-12-10 02:39:40 -0800376 The interval between RTCP packets is varied randomly over the
377 range [0.5,1.5] times the calculated interval to avoid unintended
378 synchronization of all participants
niklase@google.com470e71d2011-07-07 08:21:25 +0000379
danilchap162abd32015-12-10 02:39:40 -0800380 if we send
381 If the participant is a sender (we_sent true), the constant C is
382 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
383 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
384 number of senders.
niklase@google.com470e71d2011-07-07 08:21:25 +0000385
danilchap162abd32015-12-10 02:39:40 -0800386 if we receive only
387 If we_sent is not true, the constant C is set
388 to the average RTCP packet size divided by 75% of the RTCP
389 bandwidth. The constant n is set to the number of receivers
390 (members - senders). If the number of senders is greater than
391 25%, senders and receivers are treated together.
niklase@google.com470e71d2011-07-07 08:21:25 +0000392
danilchap162abd32015-12-10 02:39:40 -0800393 reconsideration NOT required for peer-to-peer
394 "timer reconsideration" is
395 employed. This algorithm implements a simple back-off mechanism
396 which causes users to hold back RTCP packet transmission if the
397 group sizes are increasing.
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
danilchap162abd32015-12-10 02:39:40 -0800399 n = number of members
400 C = avg_size/(rtcpBW/4)
niklase@google.com470e71d2011-07-07 08:21:25 +0000401
danilchap162abd32015-12-10 02:39:40 -0800402 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
niklase@google.com470e71d2011-07-07 08:21:25 +0000403
danilchap162abd32015-12-10 02:39:40 -0800404 4. The calculated interval T is set to a number uniformly distributed
405 between 0.5 and 1.5 times the deterministic calculated interval.
niklase@google.com470e71d2011-07-07 08:21:25 +0000406
danilchap162abd32015-12-10 02:39:40 -0800407 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
408 for the fact that the timer reconsideration algorithm converges to
409 a value of the RTCP bandwidth below the intended average
410 */
niklase@google.com470e71d2011-07-07 08:21:25 +0000411
Erik Språng242e22b2015-05-11 10:17:43 +0200412 int64_t now = clock_->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000413
Erik Språng242e22b2015-05-11 10:17:43 +0200414 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
xians@webrtc.org8738d272011-11-25 13:43:53 +0000415
pbosda903ea2015-10-02 02:36:56 -0700416 if (method_ == RtcpMode::kOff)
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000418
Erik Språng242e22b2015-05-11 10:17:43 +0200419 if (!audio_ && sendKeyframeBeforeRTP) {
Erik Språng61be2a42015-04-27 13:32:52 +0200420 // for video key-frames we want to send the RTCP before the large key-frame
421 // if we have a 100 ms margin
422 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
423 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000424
Erik Språng242e22b2015-05-11 10:17:43 +0200425 if (now >= next_time_to_send_rtcp_) {
Erik Språng61be2a42015-04-27 13:32:52 +0200426 return true;
427 } else if (now < 0x0000ffff &&
Erik Språng242e22b2015-05-11 10:17:43 +0200428 next_time_to_send_rtcp_ > 0xffff0000) { // 65 sec margin
Erik Språng61be2a42015-04-27 13:32:52 +0200429 // wrap
430 return true;
431 }
432 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000433}
434
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000435int64_t RTCPSender::SendTimeOfSendReport(uint32_t sendReport) {
Erik Språng242e22b2015-05-11 10:17:43 +0200436 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000437
Erik Språng61be2a42015-04-27 13:32:52 +0200438 // This is only saved when we are the sender
Erik Språng242e22b2015-05-11 10:17:43 +0200439 if ((last_send_report_[0] == 0) || (sendReport == 0)) {
Erik Språng61be2a42015-04-27 13:32:52 +0200440 return 0; // will be ignored
441 } else {
442 for (int i = 0; i < RTCP_NUMBER_OF_SR; ++i) {
Erik Språng242e22b2015-05-11 10:17:43 +0200443 if (last_send_report_[i] == sendReport)
444 return last_rtcp_time_[i];
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 }
Erik Språng61be2a42015-04-27 13:32:52 +0200446 }
447 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000448}
449
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000450bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
451 int64_t* time_ms) const {
Erik Språng242e22b2015-05-11 10:17:43 +0200452 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000453
454 if (last_xr_rr_.empty()) {
455 return false;
456 }
457 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
458 if (it == last_xr_rr_.end()) {
459 return false;
460 }
461 *time_ms = it->second;
462 return true;
463}
464
Erik Språngf7c57762015-12-04 10:40:35 +0100465rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSR(const RtcpContext& ctx) {
Erik Språng61be2a42015-04-27 13:32:52 +0200466 for (int i = (RTCP_NUMBER_OF_SR - 2); i >= 0; i--) {
467 // shift old
Erik Språng242e22b2015-05-11 10:17:43 +0200468 last_send_report_[i + 1] = last_send_report_[i];
469 last_rtcp_time_[i + 1] = last_rtcp_time_[i];
Erik Språng61be2a42015-04-27 13:32:52 +0200470 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000471
Erik Språngf7c57762015-12-04 10:40:35 +0100472 last_rtcp_time_[0] = Clock::NtpToMs(ctx.ntp_sec_, ctx.ntp_frac_);
473 last_send_report_[0] = (ctx.ntp_sec_ << 16) + (ctx.ntp_frac_ >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000474
Erik Språng61be2a42015-04-27 13:32:52 +0200475 // The timestamp of this RTCP packet should be estimated as the timestamp of
476 // the frame being captured at this moment. We are calculating that
477 // timestamp as the last frame's timestamp + the time since the last frame
478 // was captured.
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200479 uint32_t rtp_timestamp =
480 start_timestamp_ + last_rtp_timestamp_ +
481 (clock_->TimeInMilliseconds() - last_frame_capture_time_ms_) *
Erik Språngf7c57762015-12-04 10:40:35 +0100482 (ctx.feedback_state_.frequency_hz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000483
Erik Språngf7c57762015-12-04 10:40:35 +0100484 rtcp::SenderReport* report = new rtcp::SenderReport();
485 report->From(ssrc_);
486 report->WithNtpSec(ctx.ntp_sec_);
487 report->WithNtpFrac(ctx.ntp_frac_);
488 report->WithRtpTimestamp(rtp_timestamp);
489 report->WithPacketCount(ctx.feedback_state_.packets_sent);
490 report->WithOctetCount(ctx.feedback_state_.media_bytes_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000491
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200492 for (auto it : report_blocks_)
Erik Språngf7c57762015-12-04 10:40:35 +0100493 report->WithReportBlock(it.second);
niklase@google.com470e71d2011-07-07 08:21:25 +0000494
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200495 report_blocks_.clear();
Erik Språngf7c57762015-12-04 10:40:35 +0100496
497 return rtc::scoped_ptr<rtcp::SenderReport>(report);
niklase@google.com470e71d2011-07-07 08:21:25 +0000498}
499
Erik Språngf7c57762015-12-04 10:40:35 +0100500rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSDES(
501 const RtcpContext& ctx) {
Erik Språng0ea42d32015-06-25 14:46:16 +0200502 size_t length_cname = cname_.length();
henrikg91d6ede2015-09-17 00:24:34 -0700503 RTC_CHECK_LT(length_cname, static_cast<size_t>(RTCP_CNAME_SIZE));
niklase@google.com470e71d2011-07-07 08:21:25 +0000504
Erik Språngf7c57762015-12-04 10:40:35 +0100505 rtcp::Sdes* sdes = new rtcp::Sdes();
506 sdes->WithCName(ssrc_, cname_);
Erik Språng0ea42d32015-06-25 14:46:16 +0200507
508 for (const auto it : csrc_cnames_)
Erik Språngf7c57762015-12-04 10:40:35 +0100509 sdes->WithCName(it.first, it.second);
Erik Språng0ea42d32015-06-25 14:46:16 +0200510
Erik Språngf7c57762015-12-04 10:40:35 +0100511 return rtc::scoped_ptr<rtcp::Sdes>(sdes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000512}
513
Erik Språngf7c57762015-12-04 10:40:35 +0100514rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildRR(const RtcpContext& ctx) {
515 rtcp::ReceiverReport* report = new rtcp::ReceiverReport();
516 report->From(ssrc_);
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200517 for (auto it : report_blocks_)
Erik Språngf7c57762015-12-04 10:40:35 +0100518 report->WithReportBlock(it.second);
Erik Språng61be2a42015-04-27 13:32:52 +0200519
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200520 report_blocks_.clear();
Erik Språngf7c57762015-12-04 10:40:35 +0100521 return rtc::scoped_ptr<rtcp::ReceiverReport>(report);
niklase@google.com470e71d2011-07-07 08:21:25 +0000522}
523
Erik Språngf7c57762015-12-04 10:40:35 +0100524rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildPLI(const RtcpContext& ctx) {
525 rtcp::Pli* pli = new rtcp::Pli();
526 pli->From(ssrc_);
527 pli->To(remote_ssrc_);
Erik Språng61be2a42015-04-27 13:32:52 +0200528
Erik Språng242e22b2015-05-11 10:17:43 +0200529 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
530 "RTCPSender::PLI");
531 ++packet_type_counter_.pli_packets;
532 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_PLICount",
533 ssrc_, packet_type_counter_.pli_packets);
534
Erik Språngf7c57762015-12-04 10:40:35 +0100535 return rtc::scoped_ptr<rtcp::Pli>(pli);
Erik Språng61be2a42015-04-27 13:32:52 +0200536}
537
Erik Språngf7c57762015-12-04 10:40:35 +0100538rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildFIR(const RtcpContext& ctx) {
539 if (!ctx.repeat_)
sprang62dae192015-08-05 02:35:35 -0700540 ++sequence_number_fir_; // Do not increase if repetition.
niklase@google.com470e71d2011-07-07 08:21:25 +0000541
Erik Språngf7c57762015-12-04 10:40:35 +0100542 rtcp::Fir* fir = new rtcp::Fir();
543 fir->From(ssrc_);
544 fir->To(remote_ssrc_);
545 fir->WithCommandSeqNum(sequence_number_fir_);
Erik Språng242e22b2015-05-11 10:17:43 +0200546
547 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
548 "RTCPSender::FIR");
549 ++packet_type_counter_.fir_packets;
550 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_FIRCount",
551 ssrc_, packet_type_counter_.fir_packets);
552
Erik Språngf7c57762015-12-04 10:40:35 +0100553 return rtc::scoped_ptr<rtcp::Fir>(fir);
niklase@google.com470e71d2011-07-07 08:21:25 +0000554}
555
556/*
557 0 1 2 3
558 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
559 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
560 | First | Number | PictureID |
561 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
562*/
Erik Språngf7c57762015-12-04 10:40:35 +0100563rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildSLI(const RtcpContext& ctx) {
564 rtcp::Sli* sli = new rtcp::Sli();
565 sli->From(ssrc_);
566 sli->To(remote_ssrc_);
sprang0365a272015-08-11 01:02:37 -0700567 // Crop picture id to 6 least significant bits.
Erik Språngf7c57762015-12-04 10:40:35 +0100568 sli->WithPictureId(ctx.picture_id_ & 0x3F);
sprang0365a272015-08-11 01:02:37 -0700569
Erik Språngf7c57762015-12-04 10:40:35 +0100570 return rtc::scoped_ptr<rtcp::Sli>(sli);
niklase@google.com470e71d2011-07-07 08:21:25 +0000571}
572
573/*
574 0 1 2 3
575 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
576 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
577 | PB |0| Payload Type| Native RPSI bit string |
578 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
579 | defined per codec ... | Padding (0) |
580 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
581*/
582/*
583* Note: not generic made for VP8
584*/
Erik Språngf7c57762015-12-04 10:40:35 +0100585rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildRPSI(
586 const RtcpContext& ctx) {
587 if (ctx.feedback_state_.send_payload_type == 0xFF)
588 return nullptr;
Erik Språng242e22b2015-05-11 10:17:43 +0200589
Erik Språngf7c57762015-12-04 10:40:35 +0100590 rtcp::Rpsi* rpsi = new rtcp::Rpsi();
591 rpsi->From(ssrc_);
592 rpsi->To(remote_ssrc_);
593 rpsi->WithPayloadType(ctx.feedback_state_.send_payload_type);
594 rpsi->WithPictureId(ctx.picture_id_);
sprangcf7f54d2015-08-13 04:37:42 -0700595
Erik Språngf7c57762015-12-04 10:40:35 +0100596 return rtc::scoped_ptr<rtcp::Rpsi>(rpsi);
niklase@google.com470e71d2011-07-07 08:21:25 +0000597}
598
Erik Språngf7c57762015-12-04 10:40:35 +0100599rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildREMB(
600 const RtcpContext& ctx) {
601 rtcp::Remb* remb = new rtcp::Remb();
602 remb->From(ssrc_);
sprangdd4edc52015-08-21 04:21:51 -0700603 for (uint32_t ssrc : remb_ssrcs_)
Erik Språngf7c57762015-12-04 10:40:35 +0100604 remb->AppliesTo(ssrc);
605 remb->WithBitrateBps(remb_bitrate_);
Erik Språng61be2a42015-04-27 13:32:52 +0200606
Erik Språng242e22b2015-05-11 10:17:43 +0200607 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
608 "RTCPSender::REMB");
609
Erik Språngf7c57762015-12-04 10:40:35 +0100610 return rtc::scoped_ptr<rtcp::Remb>(remb);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000611}
612
Erik Språng61be2a42015-04-27 13:32:52 +0200613void RTCPSender::SetTargetBitrate(unsigned int target_bitrate) {
Erik Språng242e22b2015-05-11 10:17:43 +0200614 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
615 tmmbr_send_ = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +0000616}
617
Erik Språngf7c57762015-12-04 10:40:35 +0100618rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBR(
619 const RtcpContext& ctx) {
620 if (ctx.feedback_state_.module == nullptr)
621 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200622 // Before sending the TMMBR check the received TMMBN, only an owner is
623 // allowed to raise the bitrate:
624 // * If the sender is an owner of the TMMBN -> send TMMBR
625 // * If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
niklase@google.com470e71d2011-07-07 08:21:25 +0000626
Erik Språng61be2a42015-04-27 13:32:52 +0200627 // get current bounding set from RTCP receiver
628 bool tmmbrOwner = false;
629 // store in candidateSet, allocates one extra slot
Erik Språng242e22b2015-05-11 10:17:43 +0200630 TMMBRSet* candidateSet = tmmbr_help_.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000631
Erik Språng242e22b2015-05-11 10:17:43 +0200632 // holding critical_section_rtcp_sender_ while calling RTCPreceiver which
633 // will accuire criticalSectionRTCPReceiver_ is a potental deadlock but
Erik Språng61be2a42015-04-27 13:32:52 +0200634 // since RTCPreceiver is not doing the reverse we should be fine
635 int32_t lengthOfBoundingSet =
danilchap6db6cdc2015-12-15 02:54:47 -0800636 ctx.feedback_state_.module->BoundingSet(&tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +0000637
Erik Språng61be2a42015-04-27 13:32:52 +0200638 if (lengthOfBoundingSet > 0) {
639 for (int32_t i = 0; i < lengthOfBoundingSet; i++) {
Erik Språng242e22b2015-05-11 10:17:43 +0200640 if (candidateSet->Tmmbr(i) == tmmbr_send_ &&
641 candidateSet->PacketOH(i) == packet_oh_send_) {
Erik Språngf7c57762015-12-04 10:40:35 +0100642 // Do not send the same tuple.
643 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200644 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 }
Erik Språng61be2a42015-04-27 13:32:52 +0200646 if (!tmmbrOwner) {
647 // use received bounding set as candidate set
648 // add current tuple
Erik Språng242e22b2015-05-11 10:17:43 +0200649 candidateSet->SetEntry(lengthOfBoundingSet, tmmbr_send_, packet_oh_send_,
650 ssrc_);
Erik Språng61be2a42015-04-27 13:32:52 +0200651 int numCandidates = lengthOfBoundingSet + 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000652
Erik Språng61be2a42015-04-27 13:32:52 +0200653 // find bounding set
Erik Språngf7c57762015-12-04 10:40:35 +0100654 TMMBRSet* boundingSet = nullptr;
Erik Språng242e22b2015-05-11 10:17:43 +0200655 int numBoundingSet = tmmbr_help_.FindTMMBRBoundingSet(boundingSet);
Erik Språng61be2a42015-04-27 13:32:52 +0200656 if (numBoundingSet > 0 || numBoundingSet <= numCandidates)
Erik Språng242e22b2015-05-11 10:17:43 +0200657 tmmbrOwner = tmmbr_help_.IsOwner(ssrc_, numBoundingSet);
Erik Språng61be2a42015-04-27 13:32:52 +0200658 if (!tmmbrOwner) {
Erik Språngf7c57762015-12-04 10:40:35 +0100659 // Did not enter bounding set, no meaning to send this request.
660 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200661 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 }
Erik Språng61be2a42015-04-27 13:32:52 +0200663 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000664
Erik Språngf7c57762015-12-04 10:40:35 +0100665 if (!tmmbr_send_)
666 return nullptr;
sprang81a3e602015-08-21 05:30:11 -0700667
Erik Språngf7c57762015-12-04 10:40:35 +0100668 rtcp::Tmmbr* tmmbr = new rtcp::Tmmbr();
669 tmmbr->From(ssrc_);
670 tmmbr->To(remote_ssrc_);
671 tmmbr->WithBitrateKbps(tmmbr_send_);
672 tmmbr->WithOverhead(packet_oh_send_);
673
674 return rtc::scoped_ptr<rtcp::Tmmbr>(tmmbr);
Erik Språng61be2a42015-04-27 13:32:52 +0200675}
676
Erik Språngf7c57762015-12-04 10:40:35 +0100677rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildTMMBN(
678 const RtcpContext& ctx) {
Erik Språng242e22b2015-05-11 10:17:43 +0200679 TMMBRSet* boundingSet = tmmbr_help_.BoundingSetToSend();
Erik Språngf7c57762015-12-04 10:40:35 +0100680 if (boundingSet == nullptr)
681 return nullptr;
Erik Språng61be2a42015-04-27 13:32:52 +0200682
Erik Språngf7c57762015-12-04 10:40:35 +0100683 rtcp::Tmmbn* tmmbn = new rtcp::Tmmbn();
684 tmmbn->From(ssrc_);
sprangd83df502015-08-27 01:05:08 -0700685 for (uint32_t i = 0; i < boundingSet->lengthOfSet(); i++) {
686 if (boundingSet->Tmmbr(i) > 0) {
Erik Språngf7c57762015-12-04 10:40:35 +0100687 tmmbn->WithTmmbr(boundingSet->Ssrc(i), boundingSet->Tmmbr(i),
688 boundingSet->PacketOH(i));
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +0000689 }
Erik Språng61be2a42015-04-27 13:32:52 +0200690 }
sprangd83df502015-08-27 01:05:08 -0700691
Erik Språngf7c57762015-12-04 10:40:35 +0100692 return rtc::scoped_ptr<rtcp::Tmmbn>(tmmbn);
niklase@google.com470e71d2011-07-07 08:21:25 +0000693}
694
Erik Språngf7c57762015-12-04 10:40:35 +0100695rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildAPP(const RtcpContext& ctx) {
696 rtcp::App* app = new rtcp::App();
697 app->From(ssrc_);
698 app->WithSubType(app_sub_type_);
699 app->WithName(app_name_);
700 app->WithData(app_data_.get(), app_length_);
Erik Språng521875a2015-09-01 10:11:16 +0200701
Erik Språngf7c57762015-12-04 10:40:35 +0100702 return rtc::scoped_ptr<rtcp::App>(app);
Erik Språng61be2a42015-04-27 13:32:52 +0200703}
704
Erik Språngf7c57762015-12-04 10:40:35 +0100705rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK(
706 const RtcpContext& ctx) {
707 rtcp::Nack* nack = new rtcp::Nack();
708 nack->From(ssrc_);
709 nack->To(remote_ssrc_);
710 nack->WithList(ctx.nack_list_, ctx.nack_size_);
Erik Språng61be2a42015-04-27 13:32:52 +0200711
712 // Report stats.
713 NACKStringBuilder stringBuilder;
Erik Språngf7c57762015-12-04 10:40:35 +0100714 for (int idx = 0; idx < ctx.nack_size_; ++idx) {
715 stringBuilder.PushNACK(ctx.nack_list_[idx]);
716 nack_stats_.ReportRequest(ctx.nack_list_[idx]);
Erik Språng61be2a42015-04-27 13:32:52 +0200717 }
Erik Språng61be2a42015-04-27 13:32:52 +0200718 packet_type_counter_.nack_requests = nack_stats_.requests();
719 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
Erik Språng242e22b2015-05-11 10:17:43 +0200720
721 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
722 "RTCPSender::NACK", "nacks",
723 TRACE_STR_COPY(stringBuilder.GetResult().c_str()));
724 ++packet_type_counter_.nack_packets;
725 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "RTCP_NACKCount",
726 ssrc_, packet_type_counter_.nack_packets);
727
Erik Språngf7c57762015-12-04 10:40:35 +0100728 return rtc::scoped_ptr<rtcp::Nack>(nack);
Erik Språng61be2a42015-04-27 13:32:52 +0200729}
730
Erik Språngf7c57762015-12-04 10:40:35 +0100731rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildBYE(const RtcpContext& ctx) {
732 rtcp::Bye* bye = new rtcp::Bye();
733 bye->From(ssrc_);
sprangd8ee4f92015-08-24 03:25:19 -0700734 for (uint32_t csrc : csrcs_)
Erik Språngf7c57762015-12-04 10:40:35 +0100735 bye->WithCsrc(csrc);
sprangd8ee4f92015-08-24 03:25:19 -0700736
Erik Språngf7c57762015-12-04 10:40:35 +0100737 return rtc::scoped_ptr<rtcp::Bye>(bye);
niklase@google.com470e71d2011-07-07 08:21:25 +0000738}
739
Erik Språngf7c57762015-12-04 10:40:35 +0100740rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildReceiverReferenceTime(
741 const RtcpContext& ctx) {
Erik Språng61be2a42015-04-27 13:32:52 +0200742 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000743 last_xr_rr_.erase(last_xr_rr_.begin());
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000744 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
Erik Språngf7c57762015-12-04 10:40:35 +0100745 RTCPUtility::MidNtp(ctx.ntp_sec_, ctx.ntp_frac_),
746 Clock::NtpToMs(ctx.ntp_sec_, ctx.ntp_frac_)));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000747
Danil Chapovalov256e5b22016-01-15 14:16:24 +0100748 rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
Erik Språngf7c57762015-12-04 10:40:35 +0100749 xr->From(ssrc_);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000750
Erik Språngca28fdc2015-08-31 14:00:50 +0200751 rtcp::Rrtr rrtr;
Danil Chapovalovfc47ed62015-12-07 14:46:35 +0100752 rrtr.WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000753
Erik Språngf7c57762015-12-04 10:40:35 +0100754 xr->WithRrtr(&rrtr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000755
Erik Språngca28fdc2015-08-31 14:00:50 +0200756 // TODO(sprang): Merge XR report sending to contain all of RRTR, DLRR, VOIP?
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000757
Danil Chapovalov256e5b22016-01-15 14:16:24 +0100758 return rtc::scoped_ptr<rtcp::RtcpPacket>(xr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000759}
760
Erik Språngf7c57762015-12-04 10:40:35 +0100761rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildDlrr(
762 const RtcpContext& ctx) {
Danil Chapovalov256e5b22016-01-15 14:16:24 +0100763 rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
Erik Språngf7c57762015-12-04 10:40:35 +0100764 xr->From(ssrc_);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000765
Erik Språngca28fdc2015-08-31 14:00:50 +0200766 rtcp::Dlrr dlrr;
Erik Språngf7c57762015-12-04 10:40:35 +0100767 const RtcpReceiveTimeInfo& info = ctx.feedback_state_.last_xr_rr;
Erik Språngca28fdc2015-08-31 14:00:50 +0200768 dlrr.WithDlrrItem(info.sourceSSRC, info.lastRR, info.delaySinceLastRR);
769
Erik Språngf7c57762015-12-04 10:40:35 +0100770 xr->WithDlrr(&dlrr);
Erik Språngca28fdc2015-08-31 14:00:50 +0200771
Danil Chapovalov256e5b22016-01-15 14:16:24 +0100772 return rtc::scoped_ptr<rtcp::RtcpPacket>(xr);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000773}
774
Erik Språng242e22b2015-05-11 10:17:43 +0200775// TODO(sprang): Add a unit test for this, or remove if the code isn't used.
Erik Språngf7c57762015-12-04 10:40:35 +0100776rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildVoIPMetric(
777 const RtcpContext& context) {
Danil Chapovalov256e5b22016-01-15 14:16:24 +0100778 rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
Erik Språngf7c57762015-12-04 10:40:35 +0100779 xr->From(ssrc_);
Erik Språngca28fdc2015-08-31 14:00:50 +0200780
781 rtcp::VoipMetric voip;
782 voip.To(remote_ssrc_);
danilchap91941ae2015-12-15 07:06:36 -0800783 voip.WithVoipMetric(xr_voip_metric_);
Erik Språngca28fdc2015-08-31 14:00:50 +0200784
Erik Språngf7c57762015-12-04 10:40:35 +0100785 xr->WithVoipMetric(&voip);
Erik Språngca28fdc2015-08-31 14:00:50 +0200786
Danil Chapovalov256e5b22016-01-15 14:16:24 +0100787 return rtc::scoped_ptr<rtcp::RtcpPacket>(xr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000788}
789
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000790int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
Erik Språng242e22b2015-05-11 10:17:43 +0200791 RTCPPacketType packetType,
792 int32_t nack_size,
793 const uint16_t* nack_list,
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000794 bool repeat,
795 uint64_t pictureID) {
Erik Språng242e22b2015-05-11 10:17:43 +0200796 return SendCompoundRTCP(
797 feedback_state, std::set<RTCPPacketType>(&packetType, &packetType + 1),
798 nack_size, nack_list, repeat, pictureID);
799}
800
801int32_t RTCPSender::SendCompoundRTCP(
802 const FeedbackState& feedback_state,
Erik Språngf7c57762015-12-04 10:40:35 +0100803 const std::set<RTCPPacketType>& packet_types,
Erik Språng242e22b2015-05-11 10:17:43 +0200804 int32_t nack_size,
805 const uint16_t* nack_list,
806 bool repeat,
807 uint64_t pictureID) {
Erik Språngf7c57762015-12-04 10:40:35 +0100808 PacketContainer container(transport_);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000809 {
Erik Språng242e22b2015-05-11 10:17:43 +0200810 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
pbosda903ea2015-10-02 02:36:56 -0700811 if (method_ == RtcpMode::kOff) {
Erik Språng61be2a42015-04-27 13:32:52 +0200812 LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
813 return -1;
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +0000814 }
Erik Språngf7c57762015-12-04 10:40:35 +0100815
816 // We need to send our NTP even if we haven't received any reports.
817 uint32_t ntp_sec;
818 uint32_t ntp_frac;
819 clock_->CurrentNtp(ntp_sec, ntp_frac);
820 RtcpContext context(feedback_state, nack_size, nack_list, repeat, pictureID,
821 ntp_sec, ntp_frac, &container);
822
823 PrepareReport(packet_types, feedback_state);
824
825 auto it = report_flags_.begin();
826 while (it != report_flags_.end()) {
827 auto builder_it = builders_.find(it->type);
828 RTC_DCHECK(builder_it != builders_.end());
829 if (it->is_volatile) {
830 report_flags_.erase(it++);
831 } else {
832 ++it;
833 }
834
835 BuilderFunc func = builder_it->second;
836 rtc::scoped_ptr<rtcp::RtcpPacket> packet = (this->*func)(context);
837 if (packet.get() == nullptr)
838 return -1;
839 container.Append(packet.release());
840 }
841
842 if (packet_type_counter_observer_ != nullptr) {
843 packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
844 remote_ssrc_, packet_type_counter_);
845 }
846
847 RTC_DCHECK(AllVolatileFlagsConsumed());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000848 }
Erik Språng61be2a42015-04-27 13:32:52 +0200849
Erik Språngf7c57762015-12-04 10:40:35 +0100850 size_t bytes_sent = container.SendPackets();
851 return bytes_sent == 0 ? -1 : 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000852}
853
Erik Språngf7c57762015-12-04 10:40:35 +0100854void RTCPSender::PrepareReport(const std::set<RTCPPacketType>& packetTypes,
855 const FeedbackState& feedback_state) {
Erik Språng242e22b2015-05-11 10:17:43 +0200856 // Add all flags as volatile. Non volatile entries will not be overwritten
857 // and all new volatile flags added will be consumed by the end of this call.
858 SetFlags(packetTypes, true);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000859
Erik Språng61be2a42015-04-27 13:32:52 +0200860 if (packet_type_counter_.first_packet_time_ms == -1)
Erik Språng242e22b2015-05-11 10:17:43 +0200861 packet_type_counter_.first_packet_time_ms = clock_->TimeInMilliseconds();
Erik Språng61be2a42015-04-27 13:32:52 +0200862
Erik Språng242e22b2015-05-11 10:17:43 +0200863 bool generate_report;
864 if (IsFlagPresent(kRtcpSr) || IsFlagPresent(kRtcpRr)) {
865 // Report type already explicitly set, don't automatically populate.
866 generate_report = true;
henrikg91d6ede2015-09-17 00:24:34 -0700867 RTC_DCHECK(ConsumeFlag(kRtcpReport) == false);
Erik Språng242e22b2015-05-11 10:17:43 +0200868 } else {
869 generate_report =
pbosda903ea2015-10-02 02:36:56 -0700870 (ConsumeFlag(kRtcpReport) && method_ == RtcpMode::kReducedSize) ||
871 method_ == RtcpMode::kCompound;
Erik Språng242e22b2015-05-11 10:17:43 +0200872 if (generate_report)
873 SetFlag(sending_ ? kRtcpSr : kRtcpRr, true);
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000874 }
875
Erik Språng0ea42d32015-06-25 14:46:16 +0200876 if (IsFlagPresent(kRtcpSr) || (IsFlagPresent(kRtcpRr) && !cname_.empty()))
Erik Språng242e22b2015-05-11 10:17:43 +0200877 SetFlag(kRtcpSdes, true);
878
Erik Språng242e22b2015-05-11 10:17:43 +0200879 if (generate_report) {
880 if (!sending_ && xr_send_receiver_reference_time_enabled_)
881 SetFlag(kRtcpXrReceiverReferenceTime, true);
Erik Språng61be2a42015-04-27 13:32:52 +0200882 if (feedback_state.has_last_xr_rr)
Erik Språng242e22b2015-05-11 10:17:43 +0200883 SetFlag(kRtcpXrDlrrReportBlock, true);
884
885 // generate next time to send an RTCP report
danilchap47a740b2015-12-15 00:30:07 -0800886 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000887
danilchap47a740b2015-12-15 00:30:07 -0800888 if (!audio_) {
Erik Språng242e22b2015-05-11 10:17:43 +0200889 if (sending_) {
Erik Språng61be2a42015-04-27 13:32:52 +0200890 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
891 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
892 if (send_bitrate_kbit != 0)
893 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000894 }
Erik Språng61be2a42015-04-27 13:32:52 +0200895 if (minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
896 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
Erik Språng61be2a42015-04-27 13:32:52 +0200897 }
danilchap47a740b2015-12-15 00:30:07 -0800898 // The interval between RTCP packets is varied randomly over the
899 // range [1/2,3/2] times the calculated interval.
900 uint32_t timeToNext =
901 random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2);
Erik Språng242e22b2015-05-11 10:17:43 +0200902 next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000903
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000904 StatisticianMap statisticians =
905 receive_statistics_->GetActiveStatisticians();
danilchapa72e7342015-12-22 08:07:45 -0800906 RTC_DCHECK(report_blocks_.empty());
907 for (auto& it : statisticians) {
908 AddReportBlock(feedback_state, it.first, it.second);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000909 }
910 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000911}
912
danilchapa72e7342015-12-22 08:07:45 -0800913bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state,
914 uint32_t ssrc,
915 StreamStatistician* statistician) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000916 // Do we have receive statistics to send?
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000917 RtcpStatistics stats;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000918 if (!statistician->GetStatistics(&stats, true))
919 return false;
danilchapa72e7342015-12-22 08:07:45 -0800920
921 if (report_blocks_.size() >= RTCP_MAX_REPORT_BLOCKS) {
922 LOG(LS_WARNING) << "Too many report blocks.";
923 return false;
924 }
925 RTC_DCHECK(report_blocks_.find(ssrc) == report_blocks_.end());
926 rtcp::ReportBlock* block = &report_blocks_[ssrc];
927 block->To(ssrc);
928 block->WithFractionLost(stats.fraction_lost);
929 if (!block->WithCumulativeLost(stats.cumulative_lost)) {
930 report_blocks_.erase(ssrc);
931 LOG(LS_WARNING) << "Cumulative lost is oversized.";
932 return false;
933 }
934 block->WithExtHighestSeqNum(stats.extended_max_sequence_number);
935 block->WithJitter(stats.jitter);
936 block->WithLastSr(feedback_state.remote_sr);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000937
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200938 // TODO(sprang): Do we really need separate time stamps for each report?
939 // Get our NTP as late as possible to avoid a race.
940 uint32_t ntp_secs;
941 uint32_t ntp_frac;
942 clock_->CurrentNtp(ntp_secs, ntp_frac);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000943
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200944 // Delay since last received report.
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000945 if ((feedback_state.last_rr_ntp_secs != 0) ||
946 (feedback_state.last_rr_ntp_frac != 0)) {
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200947 // Get the 16 lowest bits of seconds and the 16 highest bits of fractions.
948 uint32_t now = ntp_secs & 0x0000FFFF;
Erik Språng61be2a42015-04-27 13:32:52 +0200949 now <<= 16;
Erik Språngbdc0b0d2015-06-22 15:21:24 +0200950 now += (ntp_frac & 0xffff0000) >> 16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000951
Erik Språng61be2a42015-04-27 13:32:52 +0200952 uint32_t receiveTime = feedback_state.last_rr_ntp_secs & 0x0000FFFF;
953 receiveTime <<= 16;
954 receiveTime += (feedback_state.last_rr_ntp_frac & 0xffff0000) >> 16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000955
danilchapa72e7342015-12-22 08:07:45 -0800956 block->WithDelayLastSr(now - receiveTime);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000957 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000958 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000959}
960
pbos@webrtc.org9334ac22014-11-24 08:25:50 +0000961void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
962 assert(csrcs.size() <= kRtpCsrcSize);
Erik Språng242e22b2015-05-11 10:17:43 +0200963 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
pbos@webrtc.org9334ac22014-11-24 08:25:50 +0000964 csrcs_ = csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000965}
966
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000967int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
968 uint32_t name,
969 const uint8_t* data,
970 uint16_t length) {
Erik Språng61be2a42015-04-27 13:32:52 +0200971 if (length % 4 != 0) {
972 LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
973 return -1;
974 }
Erik Språng242e22b2015-05-11 10:17:43 +0200975 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000976
Erik Språng242e22b2015-05-11 10:17:43 +0200977 SetFlag(kRtcpApp, true);
978 app_sub_type_ = subType;
979 app_name_ = name;
980 app_data_.reset(new uint8_t[length]);
981 app_length_ = length;
982 memcpy(app_data_.get(), data, length);
Erik Språng61be2a42015-04-27 13:32:52 +0200983 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000984}
985
Erik Språng61be2a42015-04-27 13:32:52 +0200986int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
Erik Språng242e22b2015-05-11 10:17:43 +0200987 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
988 memcpy(&xr_voip_metric_, VoIPMetric, sizeof(RTCPVoIPMetric));
niklase@google.com470e71d2011-07-07 08:21:25 +0000989
Erik Språng242e22b2015-05-11 10:17:43 +0200990 SetFlag(kRtcpXrVoipMetric, true);
Erik Språng61be2a42015-04-27 13:32:52 +0200991 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000992}
993
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000994void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
Erik Språng242e22b2015-05-11 10:17:43 +0200995 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
996 xr_send_receiver_reference_time_enabled_ = enable;
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000997}
998
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +0000999bool RTCPSender::RtcpXrReceiverReferenceTime() const {
Erik Språng242e22b2015-05-11 10:17:43 +02001000 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
1001 return xr_send_receiver_reference_time_enabled_;
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +00001002}
1003
niklase@google.com470e71d2011-07-07 08:21:25 +00001004// no callbacks allowed inside this function
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001005int32_t RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
1006 uint32_t maxBitrateKbit) {
Erik Språng242e22b2015-05-11 10:17:43 +02001007 CriticalSectionScoped lock(critical_section_rtcp_sender_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001008
Erik Språng242e22b2015-05-11 10:17:43 +02001009 if (0 == tmmbr_help_.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit)) {
1010 SetFlag(kRtcpTmmbn, true);
Erik Språng61be2a42015-04-27 13:32:52 +02001011 return 0;
1012 }
1013 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001014}
Erik Språng61be2a42015-04-27 13:32:52 +02001015
Erik Språng242e22b2015-05-11 10:17:43 +02001016void RTCPSender::SetFlag(RTCPPacketType type, bool is_volatile) {
1017 report_flags_.insert(ReportFlag(type, is_volatile));
1018}
1019
1020void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
1021 bool is_volatile) {
1022 for (RTCPPacketType type : types)
1023 SetFlag(type, is_volatile);
1024}
1025
1026bool RTCPSender::IsFlagPresent(RTCPPacketType type) const {
1027 return report_flags_.find(ReportFlag(type, false)) != report_flags_.end();
1028}
1029
1030bool RTCPSender::ConsumeFlag(RTCPPacketType type, bool forced) {
1031 auto it = report_flags_.find(ReportFlag(type, false));
1032 if (it == report_flags_.end())
1033 return false;
1034 if (it->is_volatile || forced)
1035 report_flags_.erase((it));
1036 return true;
1037}
1038
1039bool RTCPSender::AllVolatileFlagsConsumed() const {
1040 for (const ReportFlag& flag : report_flags_) {
1041 if (flag.is_volatile)
1042 return false;
1043 }
1044 return true;
1045}
1046
sprang233bd872015-09-08 13:25:16 -07001047bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
sprang233bd872015-09-08 13:25:16 -07001048 class Sender : public rtcp::RtcpPacket::PacketReadyCallback {
1049 public:
danilchap6db6cdc2015-12-15 02:54:47 -08001050 explicit Sender(Transport* transport)
Peter Boströmac547a62015-09-17 23:03:57 +02001051 : transport_(transport), send_failure_(false) {}
sprang233bd872015-09-08 13:25:16 -07001052
1053 void OnPacketReady(uint8_t* data, size_t length) override {
pbos2d566682015-09-28 09:59:31 -07001054 if (!transport_->SendRtcp(data, length))
sprang233bd872015-09-08 13:25:16 -07001055 send_failure_ = true;
1056 }
1057
1058 Transport* const transport_;
sprang233bd872015-09-08 13:25:16 -07001059 bool send_failure_;
sprang86fd9ed2015-09-29 04:45:43 -07001060 } sender(transport_);
sprang233bd872015-09-08 13:25:16 -07001061
1062 uint8_t buffer[IP_PACKET_SIZE];
1063 return packet.BuildExternalBuffer(buffer, IP_PACKET_SIZE, &sender) &&
1064 !sender.send_failure_;
1065}
1066
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001067} // namespace webrtc