blob: 28d90bc463701340c04da56fb300d360a539a8ff [file] [log] [blame]
Danil Chapovalov398a7c62017-10-24 17:07:05 +02001/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
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
11#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
12
13#include <utility>
Danil Chapovalov398a7c62017-10-24 17:07:05 +020014
15#include "api/call/transport.h"
16#include "modules/rtp_rtcp/include/receive_statistics.h"
17#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
18#include "modules/rtp_rtcp/source/rtcp_packet.h"
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010019#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010020#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
Danil Chapovalov319a6752017-11-30 14:56:52 +010021#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010022#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
Danil Chapovalov327c43c2017-11-27 17:23:04 +010023#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
Danil Chapovalova7e418c2017-11-21 11:08:53 +010024#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020025#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
26#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Danil Chapovalov78161ca2017-10-26 12:09:41 +020027#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010028#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
29#include "modules/rtp_rtcp/source/time_util.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020030#include "rtc_base/checks.h"
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010031#include "rtc_base/logging.h"
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010032#include "rtc_base/ptr_util.h"
33#include "rtc_base/task_queue.h"
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010034#include "rtc_base/timeutils.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020035
36namespace webrtc {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010037namespace {
38
39struct SenderReportTimes {
40 int64_t local_received_time_us;
41 NtpTime remote_sent_time;
42};
43
44} // namespace
45
46struct RtcpTransceiverImpl::RemoteSenderState {
47 uint8_t fir_sequence_number = 0;
48 rtc::Optional<SenderReportTimes> last_received_sender_report;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010049 std::vector<MediaReceiverRtcpObserver*> observers;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010050};
Danil Chapovalov398a7c62017-10-24 17:07:05 +020051
52// Helper to put several RTCP packets into lower layer datagram composing
53// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
Danil Chapovalova7e418c2017-11-21 11:08:53 +010054// TODO(danilchap): When in compound mode and packets are so many that several
55// compound RTCP packets need to be generated, ensure each packet is compound.
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010056class RtcpTransceiverImpl::PacketSender {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020057 public:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010058 PacketSender(rtcp::RtcpPacket::PacketReadyCallback callback,
59 size_t max_packet_size)
60 : callback_(callback), max_packet_size_(max_packet_size) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020061 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
62 }
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010063 ~PacketSender() { RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020064
65 // Appends a packet to pending compound packet.
66 // Sends rtcp compound packet if buffer was already full and resets buffer.
67 void AppendPacket(const rtcp::RtcpPacket& packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010068 packet.Create(buffer_, &index_, max_packet_size_, callback_);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020069 }
70
71 // Sends pending rtcp compound packet.
72 void Send() {
73 if (index_ > 0) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010074 callback_(rtc::ArrayView<const uint8_t>(buffer_, index_));
Danil Chapovalov398a7c62017-10-24 17:07:05 +020075 index_ = 0;
76 }
77 }
78
Danil Chapovalova7e418c2017-11-21 11:08:53 +010079 bool IsEmpty() const { return index_ == 0; }
80
Danil Chapovalov398a7c62017-10-24 17:07:05 +020081 private:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010082 const rtcp::RtcpPacket::PacketReadyCallback callback_;
Danil Chapovalov398a7c62017-10-24 17:07:05 +020083 const size_t max_packet_size_;
84 size_t index_ = 0;
85 uint8_t buffer_[IP_PACKET_SIZE];
86};
87
Danil Chapovalov398a7c62017-10-24 17:07:05 +020088RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010089 : config_(config), ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020090 RTC_CHECK(config_.Validate());
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010091 if (config_.schedule_periodic_compound_packets)
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010092 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020093}
94
95RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
96
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010097void RtcpTransceiverImpl::AddMediaReceiverObserver(
98 uint32_t remote_ssrc,
99 MediaReceiverRtcpObserver* observer) {
100 auto& stored = remote_senders_[remote_ssrc].observers;
101 RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
102 stored.push_back(observer);
103}
104
105void RtcpTransceiverImpl::RemoveMediaReceiverObserver(
106 uint32_t remote_ssrc,
107 MediaReceiverRtcpObserver* observer) {
108 auto remote_sender_it = remote_senders_.find(remote_ssrc);
109 if (remote_sender_it == remote_senders_.end())
110 return;
111 auto& stored = remote_sender_it->second.observers;
112 auto it = std::find(stored.begin(), stored.end(), observer);
113 if (it == stored.end())
114 return;
115 stored.erase(it);
116}
117
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100118void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
119 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100120 while (!packet.empty()) {
121 rtcp::CommonHeader rtcp_block;
122 if (!rtcp_block.Parse(packet.data(), packet.size()))
123 return;
124
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100125 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100126
127 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
128 packet = packet.subview(rtcp_block.packet_size());
129 }
130}
131
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200132void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100133 SendPeriodicCompoundPacket();
134 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100135}
136
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100137void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100138 std::vector<uint32_t> ssrcs) {
139 RTC_DCHECK_GE(bitrate_bps, 0);
140 remb_.emplace();
141 remb_->SetSsrcs(std::move(ssrcs));
142 remb_->SetBitrateBps(bitrate_bps);
143 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
144 // immideately on large bitrate change when there is one RtcpTransceiver per
145 // rtp transport.
146}
147
148void RtcpTransceiverImpl::UnsetRemb() {
149 remb_.reset();
150}
151
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100152void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
153 // Unlike other senders, this functions just tries to send packet away and
154 // disregard rtcp_mode, max_packet_size or anything else.
155 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
156 // TransportFeedback inside this class when there is one per rtp transport.
157 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
158}
159
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100160void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
161 std::vector<uint16_t> sequence_numbers) {
162 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100163 rtcp::Nack nack;
164 nack.SetSenderSsrc(config_.feedback_ssrc);
165 nack.SetMediaSsrc(ssrc);
166 nack.SetPacketIds(std::move(sequence_numbers));
167 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100168}
169
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100170void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
171 rtcp::Pli pli;
172 pli.SetSenderSsrc(config_.feedback_ssrc);
173 pli.SetMediaSsrc(ssrc);
174 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100175}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100176
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100177void RtcpTransceiverImpl::SendFullIntraRequest(
178 rtc::ArrayView<const uint32_t> ssrcs) {
179 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100180 rtcp::Fir fir;
181 fir.SetSenderSsrc(config_.feedback_ssrc);
182 for (uint32_t media_ssrc : ssrcs)
183 fir.AddRequestTo(media_ssrc,
184 remote_senders_[media_ssrc].fir_sequence_number++);
185 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100186}
187
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100188void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100189 const rtcp::CommonHeader& rtcp_packet_header,
190 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100191 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100192 case rtcp::Bye::kPacketType:
193 HandleBye(rtcp_packet_header);
194 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100195 case rtcp::SenderReport::kPacketType:
196 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100197 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100198 case rtcp::ExtendedReports::kPacketType:
199 HandleExtendedReports(rtcp_packet_header, now_us);
200 break;
201 }
202}
203
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100204void RtcpTransceiverImpl::HandleBye(
205 const rtcp::CommonHeader& rtcp_packet_header) {
206 rtcp::Bye bye;
207 if (!bye.Parse(rtcp_packet_header))
208 return;
209 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
210 if (remote_sender_it == remote_senders_.end())
211 return;
212 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
213 observer->OnBye(bye.sender_ssrc());
214}
215
Danil Chapovalov319a6752017-11-30 14:56:52 +0100216void RtcpTransceiverImpl::HandleSenderReport(
217 const rtcp::CommonHeader& rtcp_packet_header,
218 int64_t now_us) {
219 rtcp::SenderReport sender_report;
220 if (!sender_report.Parse(rtcp_packet_header))
221 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100222 RemoteSenderState& remote_sender =
223 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalov319a6752017-11-30 14:56:52 +0100224 rtc::Optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100225 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100226 last.emplace();
227 last->local_received_time_us = now_us;
228 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100229
230 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
231 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
232 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100233}
234
235void RtcpTransceiverImpl::HandleExtendedReports(
236 const rtcp::CommonHeader& rtcp_packet_header,
237 int64_t now_us) {
238 rtcp::ExtendedReports extended_reports;
239 if (!extended_reports.Parse(rtcp_packet_header))
240 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100241
242 if (extended_reports.dlrr())
243 HandleDlrr(extended_reports.dlrr(), now_us);
244
245 if (extended_reports.target_bitrate())
246 HandleTargetBitrate(*extended_reports.target_bitrate(),
247 extended_reports.sender_ssrc());
248}
249
250void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
251 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
252 return;
253
254 // Delay and last_rr are transferred using 32bit compact ntp resolution.
255 // Convert packet arrival time to same format through 64bit ntp format.
256 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
257 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
258 if (rti.ssrc != config_.feedback_ssrc)
259 continue;
260 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
261 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
262 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100263 }
264}
265
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100266void RtcpTransceiverImpl::HandleTargetBitrate(
267 const rtcp::TargetBitrate& target_bitrate,
268 uint32_t remote_ssrc) {
269 auto remote_sender_it = remote_senders_.find(remote_ssrc);
270 if (remote_sender_it == remote_senders_.end() ||
271 remote_sender_it->second.observers.empty())
272 return;
273
274 // Convert rtcp::TargetBitrate to BitrateAllocation from common types.
275 BitrateAllocation bitrate_allocation;
276 for (const rtcp::TargetBitrate::BitrateItem& item :
277 target_bitrate.GetTargetBitrates()) {
278 if (item.spatial_layer >= kMaxSpatialLayers ||
279 item.temporal_layer >= kMaxTemporalStreams) {
280 RTC_DLOG(LS_WARNING)
281 << config_.debug_id
282 << "Invalid incoming TargetBitrate with spatial layer "
283 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
284 continue;
285 }
286 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
287 item.target_bitrate_kbps * 1000);
288 }
289
290 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
291 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
292}
293
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100294void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
295 if (!config_.schedule_periodic_compound_packets)
296 return;
297 // Stop existent send task.
298 ptr_factory_.InvalidateWeakPtrs();
299 SchedulePeriodicCompoundPackets(config_.report_period_ms);
300}
301
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100302void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100303 class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100304 public:
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100305 SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
306 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100307 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
308 bool Run() override {
309 RTC_DCHECK(task_queue_->IsCurrent());
310 if (!ptr_)
311 return true;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100312 ptr_->SendPeriodicCompoundPacket();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100313 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
314 ptr_->config_.report_period_ms);
315 return false;
316 }
317
318 private:
319 rtc::TaskQueue* const task_queue_;
320 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
321 };
322
323 RTC_DCHECK(config_.schedule_periodic_compound_packets);
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100324
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100325 auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100326 config_.task_queue, ptr_factory_.GetWeakPtr());
327 if (delay_ms > 0)
328 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
329 else
330 config_.task_queue->PostTask(std::move(task));
331}
332
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100333void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
334 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100335 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100336 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100337 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100338 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100339 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100340 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100341
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200342 if (!config_.cname.empty()) {
343 rtcp::Sdes sdes;
344 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
345 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
346 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100347 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200348 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100349 if (remb_) {
350 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100351 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100352 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100353 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
354 // SenderReport instead of ReceiverReport
355 // when RtcpTransceiver supports rtp senders.
356 if (config_.non_sender_rtt_measurement) {
357 rtcp::ExtendedReports xr;
358
359 rtcp::Rrtr rrtr;
360 rrtr.SetNtp(TimeMicrosToNtp(now_us));
361 xr.SetRrtr(rrtr);
362
363 xr.SetSenderSsrc(sender_ssrc);
364 sender->AppendPacket(xr);
365 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100366}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200367
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100368void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100369 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
370 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
371 };
372 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100373 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200374 sender.Send();
375}
376
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100377void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100378 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100379 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
380 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
381 };
382 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100383 // Compound mode requires every sent rtcp packet to be compound, i.e. start
384 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100385 if (config_.rtcp_mode == RtcpMode::kCompound)
386 CreateCompoundPacket(&sender);
387
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100388 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100389 sender.Send();
390
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100391 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100392 if (config_.rtcp_mode == RtcpMode::kCompound)
393 ReschedulePeriodicCompoundPackets();
394}
395
Danil Chapovalov319a6752017-11-30 14:56:52 +0100396std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
397 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100398 if (!config_.receive_statistics)
399 return {};
400 // TODO(danilchap): Support sending more than
401 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
402 std::vector<rtcp::ReportBlock> report_blocks =
403 config_.receive_statistics->RtcpReportBlocks(
404 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
405 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100406 auto it = remote_senders_.find(report_block.source_ssrc());
407 if (it == remote_senders_.end() || !it->second.last_received_sender_report)
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100408 continue;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100409 const SenderReportTimes& last_sender_report =
410 *it->second.last_received_sender_report;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100411 report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time));
412 report_block.SetDelayLastSr(SaturatedUsToCompactNtp(
Danil Chapovalov319a6752017-11-30 14:56:52 +0100413 now_us - last_sender_report.local_received_time_us));
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100414 }
415 return report_blocks;
416}
417
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200418} // namespace webrtc