blob: a58de8c126b54a4b9f3b675bb52683049b095184 [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 Chapovalove3927c52018-03-06 14:33:20 +010089 : config_(config),
90 ready_to_send_(config.initial_ready_to_send),
91 ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020092 RTC_CHECK(config_.Validate());
Danil Chapovalove3927c52018-03-06 14:33:20 +010093 if (ready_to_send_ && config_.schedule_periodic_compound_packets)
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010094 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020095}
96
97RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
98
Danil Chapovalova32d7102017-12-14 17:28:27 +010099void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100100 uint32_t remote_ssrc,
101 MediaReceiverRtcpObserver* observer) {
102 auto& stored = remote_senders_[remote_ssrc].observers;
103 RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
104 stored.push_back(observer);
105}
106
Danil Chapovalova32d7102017-12-14 17:28:27 +0100107void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100108 uint32_t remote_ssrc,
109 MediaReceiverRtcpObserver* observer) {
110 auto remote_sender_it = remote_senders_.find(remote_ssrc);
111 if (remote_sender_it == remote_senders_.end())
112 return;
113 auto& stored = remote_sender_it->second.observers;
114 auto it = std::find(stored.begin(), stored.end(), observer);
115 if (it == stored.end())
116 return;
117 stored.erase(it);
118}
119
Danil Chapovalove3927c52018-03-06 14:33:20 +0100120void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
121 if (config_.schedule_periodic_compound_packets) {
122 if (ready_to_send_ && !ready) // Stop existent send task.
123 ptr_factory_.InvalidateWeakPtrs();
124
125 if (!ready_to_send_ && ready) // Restart periodic sending.
126 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
127 }
128 ready_to_send_ = ready;
129}
130
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100131void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
132 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100133 while (!packet.empty()) {
134 rtcp::CommonHeader rtcp_block;
135 if (!rtcp_block.Parse(packet.data(), packet.size()))
136 return;
137
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100138 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100139
140 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
141 packet = packet.subview(rtcp_block.packet_size());
142 }
143}
144
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200145void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100146 if (!ready_to_send_)
147 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100148 SendPeriodicCompoundPacket();
149 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100150}
151
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100152void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100153 std::vector<uint32_t> ssrcs) {
154 RTC_DCHECK_GE(bitrate_bps, 0);
155 remb_.emplace();
156 remb_->SetSsrcs(std::move(ssrcs));
157 remb_->SetBitrateBps(bitrate_bps);
158 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
159 // immideately on large bitrate change when there is one RtcpTransceiver per
160 // rtp transport.
161}
162
163void RtcpTransceiverImpl::UnsetRemb() {
164 remb_.reset();
165}
166
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100167void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100168 if (!ready_to_send_)
169 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100170 // Unlike other senders, this functions just tries to send packet away and
171 // disregard rtcp_mode, max_packet_size or anything else.
172 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
173 // TransportFeedback inside this class when there is one per rtp transport.
174 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
175}
176
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100177void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
178 std::vector<uint16_t> sequence_numbers) {
179 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100180 if (!ready_to_send_)
181 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100182 rtcp::Nack nack;
183 nack.SetSenderSsrc(config_.feedback_ssrc);
184 nack.SetMediaSsrc(ssrc);
185 nack.SetPacketIds(std::move(sequence_numbers));
186 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100187}
188
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100189void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100190 if (!ready_to_send_)
191 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100192 rtcp::Pli pli;
193 pli.SetSenderSsrc(config_.feedback_ssrc);
194 pli.SetMediaSsrc(ssrc);
195 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100196}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100197
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100198void RtcpTransceiverImpl::SendFullIntraRequest(
199 rtc::ArrayView<const uint32_t> ssrcs) {
200 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100201 if (!ready_to_send_)
202 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100203 rtcp::Fir fir;
204 fir.SetSenderSsrc(config_.feedback_ssrc);
205 for (uint32_t media_ssrc : ssrcs)
206 fir.AddRequestTo(media_ssrc,
207 remote_senders_[media_ssrc].fir_sequence_number++);
208 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100209}
210
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100211void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100212 const rtcp::CommonHeader& rtcp_packet_header,
213 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100214 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100215 case rtcp::Bye::kPacketType:
216 HandleBye(rtcp_packet_header);
217 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100218 case rtcp::SenderReport::kPacketType:
219 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100220 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100221 case rtcp::ExtendedReports::kPacketType:
222 HandleExtendedReports(rtcp_packet_header, now_us);
223 break;
224 }
225}
226
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100227void RtcpTransceiverImpl::HandleBye(
228 const rtcp::CommonHeader& rtcp_packet_header) {
229 rtcp::Bye bye;
230 if (!bye.Parse(rtcp_packet_header))
231 return;
232 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
233 if (remote_sender_it == remote_senders_.end())
234 return;
235 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
236 observer->OnBye(bye.sender_ssrc());
237}
238
Danil Chapovalov319a6752017-11-30 14:56:52 +0100239void RtcpTransceiverImpl::HandleSenderReport(
240 const rtcp::CommonHeader& rtcp_packet_header,
241 int64_t now_us) {
242 rtcp::SenderReport sender_report;
243 if (!sender_report.Parse(rtcp_packet_header))
244 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100245 RemoteSenderState& remote_sender =
246 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalov319a6752017-11-30 14:56:52 +0100247 rtc::Optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100248 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100249 last.emplace();
250 last->local_received_time_us = now_us;
251 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100252
253 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
254 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
255 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100256}
257
258void RtcpTransceiverImpl::HandleExtendedReports(
259 const rtcp::CommonHeader& rtcp_packet_header,
260 int64_t now_us) {
261 rtcp::ExtendedReports extended_reports;
262 if (!extended_reports.Parse(rtcp_packet_header))
263 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100264
265 if (extended_reports.dlrr())
266 HandleDlrr(extended_reports.dlrr(), now_us);
267
268 if (extended_reports.target_bitrate())
269 HandleTargetBitrate(*extended_reports.target_bitrate(),
270 extended_reports.sender_ssrc());
271}
272
273void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
274 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
275 return;
276
277 // Delay and last_rr are transferred using 32bit compact ntp resolution.
278 // Convert packet arrival time to same format through 64bit ntp format.
279 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
280 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
281 if (rti.ssrc != config_.feedback_ssrc)
282 continue;
283 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
284 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
285 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100286 }
287}
288
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100289void RtcpTransceiverImpl::HandleTargetBitrate(
290 const rtcp::TargetBitrate& target_bitrate,
291 uint32_t remote_ssrc) {
292 auto remote_sender_it = remote_senders_.find(remote_ssrc);
293 if (remote_sender_it == remote_senders_.end() ||
294 remote_sender_it->second.observers.empty())
295 return;
296
Erik Språng566124a2018-04-23 12:32:22 +0200297 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
298 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100299 for (const rtcp::TargetBitrate::BitrateItem& item :
300 target_bitrate.GetTargetBitrates()) {
301 if (item.spatial_layer >= kMaxSpatialLayers ||
302 item.temporal_layer >= kMaxTemporalStreams) {
303 RTC_DLOG(LS_WARNING)
304 << config_.debug_id
305 << "Invalid incoming TargetBitrate with spatial layer "
306 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
307 continue;
308 }
309 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
310 item.target_bitrate_kbps * 1000);
311 }
312
313 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
314 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
315}
316
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100317void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
318 if (!config_.schedule_periodic_compound_packets)
319 return;
320 // Stop existent send task.
321 ptr_factory_.InvalidateWeakPtrs();
322 SchedulePeriodicCompoundPackets(config_.report_period_ms);
323}
324
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100325void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100326 class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100327 public:
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100328 SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
329 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100330 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
331 bool Run() override {
332 RTC_DCHECK(task_queue_->IsCurrent());
333 if (!ptr_)
334 return true;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100335 ptr_->SendPeriodicCompoundPacket();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100336 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
337 ptr_->config_.report_period_ms);
338 return false;
339 }
340
341 private:
342 rtc::TaskQueue* const task_queue_;
343 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
344 };
345
346 RTC_DCHECK(config_.schedule_periodic_compound_packets);
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100347
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100348 auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100349 config_.task_queue, ptr_factory_.GetWeakPtr());
350 if (delay_ms > 0)
351 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
352 else
353 config_.task_queue->PostTask(std::move(task));
354}
355
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100356void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
357 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100358 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100359 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100360 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100361 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100362 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100363 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100364
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200365 if (!config_.cname.empty()) {
366 rtcp::Sdes sdes;
367 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
368 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
369 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100370 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200371 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100372 if (remb_) {
373 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100374 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100375 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100376 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
377 // SenderReport instead of ReceiverReport
378 // when RtcpTransceiver supports rtp senders.
379 if (config_.non_sender_rtt_measurement) {
380 rtcp::ExtendedReports xr;
381
382 rtcp::Rrtr rrtr;
383 rrtr.SetNtp(TimeMicrosToNtp(now_us));
384 xr.SetRrtr(rrtr);
385
386 xr.SetSenderSsrc(sender_ssrc);
387 sender->AppendPacket(xr);
388 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100389}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200390
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100391void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100392 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
393 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
394 };
395 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100396 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200397 sender.Send();
398}
399
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100400void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100401 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100402 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
403 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
404 };
405 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100406 // Compound mode requires every sent rtcp packet to be compound, i.e. start
407 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100408 if (config_.rtcp_mode == RtcpMode::kCompound)
409 CreateCompoundPacket(&sender);
410
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100411 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100412 sender.Send();
413
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100414 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100415 if (config_.rtcp_mode == RtcpMode::kCompound)
416 ReschedulePeriodicCompoundPackets();
417}
418
Danil Chapovalov319a6752017-11-30 14:56:52 +0100419std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
420 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100421 if (!config_.receive_statistics)
422 return {};
423 // TODO(danilchap): Support sending more than
424 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
425 std::vector<rtcp::ReportBlock> report_blocks =
426 config_.receive_statistics->RtcpReportBlocks(
427 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100428 uint32_t last_sr = 0;
429 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100430 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100431 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100432 if (it == remote_senders_.end() ||
433 !it->second.last_received_sender_report) {
434 if (config_.avoid_zero_last_sr_in_last_report_block && last_sr != 0) {
435 // Simulate behaviour of the RtcpSender to avoid hitting bug in
436 // RtcpReceiver.
437 report_block.SetLastSr(last_sr);
438 report_block.SetDelayLastSr(last_delay);
439 }
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100440 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100441 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100442 const SenderReportTimes& last_sender_report =
443 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100444 last_sr = CompactNtp(last_sender_report.remote_sent_time);
445 last_delay = SaturatedUsToCompactNtp(
446 now_us - last_sender_report.local_received_time_us);
447 report_block.SetLastSr(last_sr);
448 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100449 }
450 return report_blocks;
451}
452
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200453} // namespace webrtc