blob: 6a2caab06cf4d9cfb76321b5526c09fa18baeeba [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 Chapovalovd3282292017-11-13 13:46:02 +0100137void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
138 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 Chapovalov327c43c2017-11-27 17:23:04 +0100152void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
153 std::vector<uint16_t> sequence_numbers) {
154 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100155 rtcp::Nack nack;
156 nack.SetSenderSsrc(config_.feedback_ssrc);
157 nack.SetMediaSsrc(ssrc);
158 nack.SetPacketIds(std::move(sequence_numbers));
159 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100160}
161
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100162void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
163 rtcp::Pli pli;
164 pli.SetSenderSsrc(config_.feedback_ssrc);
165 pli.SetMediaSsrc(ssrc);
166 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100167}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100168
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100169void RtcpTransceiverImpl::SendFullIntraRequest(
170 rtc::ArrayView<const uint32_t> ssrcs) {
171 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100172 rtcp::Fir fir;
173 fir.SetSenderSsrc(config_.feedback_ssrc);
174 for (uint32_t media_ssrc : ssrcs)
175 fir.AddRequestTo(media_ssrc,
176 remote_senders_[media_ssrc].fir_sequence_number++);
177 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100178}
179
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100180void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100181 const rtcp::CommonHeader& rtcp_packet_header,
182 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100183 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100184 case rtcp::Bye::kPacketType:
185 HandleBye(rtcp_packet_header);
186 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100187 case rtcp::SenderReport::kPacketType:
188 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100189 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100190 case rtcp::ExtendedReports::kPacketType:
191 HandleExtendedReports(rtcp_packet_header, now_us);
192 break;
193 }
194}
195
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100196void RtcpTransceiverImpl::HandleBye(
197 const rtcp::CommonHeader& rtcp_packet_header) {
198 rtcp::Bye bye;
199 if (!bye.Parse(rtcp_packet_header))
200 return;
201 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
202 if (remote_sender_it == remote_senders_.end())
203 return;
204 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
205 observer->OnBye(bye.sender_ssrc());
206}
207
Danil Chapovalov319a6752017-11-30 14:56:52 +0100208void RtcpTransceiverImpl::HandleSenderReport(
209 const rtcp::CommonHeader& rtcp_packet_header,
210 int64_t now_us) {
211 rtcp::SenderReport sender_report;
212 if (!sender_report.Parse(rtcp_packet_header))
213 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100214 RemoteSenderState& remote_sender =
215 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalov319a6752017-11-30 14:56:52 +0100216 rtc::Optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100217 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100218 last.emplace();
219 last->local_received_time_us = now_us;
220 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100221
222 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
223 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
224 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100225}
226
227void RtcpTransceiverImpl::HandleExtendedReports(
228 const rtcp::CommonHeader& rtcp_packet_header,
229 int64_t now_us) {
230 rtcp::ExtendedReports extended_reports;
231 if (!extended_reports.Parse(rtcp_packet_header))
232 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100233
234 if (extended_reports.dlrr())
235 HandleDlrr(extended_reports.dlrr(), now_us);
236
237 if (extended_reports.target_bitrate())
238 HandleTargetBitrate(*extended_reports.target_bitrate(),
239 extended_reports.sender_ssrc());
240}
241
242void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
243 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
244 return;
245
246 // Delay and last_rr are transferred using 32bit compact ntp resolution.
247 // Convert packet arrival time to same format through 64bit ntp format.
248 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
249 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
250 if (rti.ssrc != config_.feedback_ssrc)
251 continue;
252 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
253 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
254 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100255 }
256}
257
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100258void RtcpTransceiverImpl::HandleTargetBitrate(
259 const rtcp::TargetBitrate& target_bitrate,
260 uint32_t remote_ssrc) {
261 auto remote_sender_it = remote_senders_.find(remote_ssrc);
262 if (remote_sender_it == remote_senders_.end() ||
263 remote_sender_it->second.observers.empty())
264 return;
265
266 // Convert rtcp::TargetBitrate to BitrateAllocation from common types.
267 BitrateAllocation bitrate_allocation;
268 for (const rtcp::TargetBitrate::BitrateItem& item :
269 target_bitrate.GetTargetBitrates()) {
270 if (item.spatial_layer >= kMaxSpatialLayers ||
271 item.temporal_layer >= kMaxTemporalStreams) {
272 RTC_DLOG(LS_WARNING)
273 << config_.debug_id
274 << "Invalid incoming TargetBitrate with spatial layer "
275 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
276 continue;
277 }
278 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
279 item.target_bitrate_kbps * 1000);
280 }
281
282 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
283 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
284}
285
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100286void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
287 if (!config_.schedule_periodic_compound_packets)
288 return;
289 // Stop existent send task.
290 ptr_factory_.InvalidateWeakPtrs();
291 SchedulePeriodicCompoundPackets(config_.report_period_ms);
292}
293
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100294void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100295 class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100296 public:
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100297 SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
298 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100299 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
300 bool Run() override {
301 RTC_DCHECK(task_queue_->IsCurrent());
302 if (!ptr_)
303 return true;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100304 ptr_->SendPeriodicCompoundPacket();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100305 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
306 ptr_->config_.report_period_ms);
307 return false;
308 }
309
310 private:
311 rtc::TaskQueue* const task_queue_;
312 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
313 };
314
315 RTC_DCHECK(config_.schedule_periodic_compound_packets);
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100316
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100317 auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100318 config_.task_queue, ptr_factory_.GetWeakPtr());
319 if (delay_ms > 0)
320 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
321 else
322 config_.task_queue->PostTask(std::move(task));
323}
324
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100325void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
326 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100327 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100328 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100329 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100330 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100331 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100332 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100333
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200334 if (!config_.cname.empty()) {
335 rtcp::Sdes sdes;
336 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
337 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
338 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100339 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200340 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100341 if (remb_) {
342 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100343 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100344 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100345 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
346 // SenderReport instead of ReceiverReport
347 // when RtcpTransceiver supports rtp senders.
348 if (config_.non_sender_rtt_measurement) {
349 rtcp::ExtendedReports xr;
350
351 rtcp::Rrtr rrtr;
352 rrtr.SetNtp(TimeMicrosToNtp(now_us));
353 xr.SetRrtr(rrtr);
354
355 xr.SetSenderSsrc(sender_ssrc);
356 sender->AppendPacket(xr);
357 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100358}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200359
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100360void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100361 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
362 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
363 };
364 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100365 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200366 sender.Send();
367}
368
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100369void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100370 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100371 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
372 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
373 };
374 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100375 // Compound mode requires every sent rtcp packet to be compound, i.e. start
376 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100377 if (config_.rtcp_mode == RtcpMode::kCompound)
378 CreateCompoundPacket(&sender);
379
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100380 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100381 sender.Send();
382
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100383 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100384 if (config_.rtcp_mode == RtcpMode::kCompound)
385 ReschedulePeriodicCompoundPackets();
386}
387
Danil Chapovalov319a6752017-11-30 14:56:52 +0100388std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
389 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100390 if (!config_.receive_statistics)
391 return {};
392 // TODO(danilchap): Support sending more than
393 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
394 std::vector<rtcp::ReportBlock> report_blocks =
395 config_.receive_statistics->RtcpReportBlocks(
396 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
397 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100398 auto it = remote_senders_.find(report_block.source_ssrc());
399 if (it == remote_senders_.end() || !it->second.last_received_sender_report)
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100400 continue;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100401 const SenderReportTimes& last_sender_report =
402 *it->second.last_received_sender_report;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100403 report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time));
404 report_block.SetDelayLastSr(SaturatedUsToCompactNtp(
Danil Chapovalov319a6752017-11-30 14:56:52 +0100405 now_us - last_sender_report.local_received_time_us));
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100406 }
407 return report_blocks;
408}
409
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200410} // namespace webrtc