blob: 5acad08db990673a1aad4a9ab364708f0806c9fe [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
Karl Wiberg918f50c2018-07-05 11:40:33 +020015#include "absl/memory/memory.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020016#include "api/call/transport.h"
Erik Språngeeaa8f92018-05-17 12:35:56 +020017#include "api/video/video_bitrate_allocation.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020018#include "modules/rtp_rtcp/include/receive_statistics.h"
19#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
20#include "modules/rtp_rtcp/source/rtcp_packet.h"
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010021#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010022#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
Danil Chapovalov319a6752017-11-30 14:56:52 +010023#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010024#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
Danil Chapovalov327c43c2017-11-27 17:23:04 +010025#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
Danil Chapovalova7e418c2017-11-21 11:08:53 +010026#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020027#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
28#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Danil Chapovalov78161ca2017-10-26 12:09:41 +020029#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010030#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
31#include "modules/rtp_rtcp/source/time_util.h"
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +020032#include "rtc_base/cancelable_periodic_task.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020033#include "rtc_base/checks.h"
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010034#include "rtc_base/logging.h"
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010035#include "rtc_base/task_queue.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "rtc_base/time_utils.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020037
38namespace webrtc {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010039namespace {
40
41struct SenderReportTimes {
42 int64_t local_received_time_us;
43 NtpTime remote_sent_time;
44};
45
46} // namespace
47
48struct RtcpTransceiverImpl::RemoteSenderState {
49 uint8_t fir_sequence_number = 0;
Danil Chapovalovd264df52018-06-14 12:59:38 +020050 absl::optional<SenderReportTimes> last_received_sender_report;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010051 std::vector<MediaReceiverRtcpObserver*> observers;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010052};
Danil Chapovalov398a7c62017-10-24 17:07:05 +020053
54// Helper to put several RTCP packets into lower layer datagram composing
55// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
Danil Chapovalova7e418c2017-11-21 11:08:53 +010056// TODO(danilchap): When in compound mode and packets are so many that several
57// compound RTCP packets need to be generated, ensure each packet is compound.
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010058class RtcpTransceiverImpl::PacketSender {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020059 public:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010060 PacketSender(rtcp::RtcpPacket::PacketReadyCallback callback,
61 size_t max_packet_size)
62 : callback_(callback), max_packet_size_(max_packet_size) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020063 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
64 }
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010065 ~PacketSender() { RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020066
67 // Appends a packet to pending compound packet.
68 // Sends rtcp compound packet if buffer was already full and resets buffer.
69 void AppendPacket(const rtcp::RtcpPacket& packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010070 packet.Create(buffer_, &index_, max_packet_size_, callback_);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020071 }
72
73 // Sends pending rtcp compound packet.
74 void Send() {
75 if (index_ > 0) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010076 callback_(rtc::ArrayView<const uint8_t>(buffer_, index_));
Danil Chapovalov398a7c62017-10-24 17:07:05 +020077 index_ = 0;
78 }
79 }
80
Danil Chapovalova7e418c2017-11-21 11:08:53 +010081 bool IsEmpty() const { return index_ == 0; }
82
Danil Chapovalov398a7c62017-10-24 17:07:05 +020083 private:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010084 const rtcp::RtcpPacket::PacketReadyCallback callback_;
Danil Chapovalov398a7c62017-10-24 17:07:05 +020085 const size_t max_packet_size_;
86 size_t index_ = 0;
87 uint8_t buffer_[IP_PACKET_SIZE];
88};
89
Danil Chapovalov398a7c62017-10-24 17:07:05 +020090RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +020091 : config_(config), ready_to_send_(config.initial_ready_to_send) {
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
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +020097RtcpTransceiverImpl::~RtcpTransceiverImpl() {
98 // If RtcpTransceiverImpl is destroyed off task queue, assume it is destroyed
99 // after TaskQueue. In that case there is no need to Cancel periodic task.
100 if (config_.task_queue == rtc::TaskQueue::Current()) {
101 periodic_task_handle_.Cancel();
102 }
103}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200104
Danil Chapovalova32d7102017-12-14 17:28:27 +0100105void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100106 uint32_t remote_ssrc,
107 MediaReceiverRtcpObserver* observer) {
108 auto& stored = remote_senders_[remote_ssrc].observers;
109 RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
110 stored.push_back(observer);
111}
112
Danil Chapovalova32d7102017-12-14 17:28:27 +0100113void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100114 uint32_t remote_ssrc,
115 MediaReceiverRtcpObserver* observer) {
116 auto remote_sender_it = remote_senders_.find(remote_ssrc);
117 if (remote_sender_it == remote_senders_.end())
118 return;
119 auto& stored = remote_sender_it->second.observers;
120 auto it = std::find(stored.begin(), stored.end(), observer);
121 if (it == stored.end())
122 return;
123 stored.erase(it);
124}
125
Danil Chapovalove3927c52018-03-06 14:33:20 +0100126void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
127 if (config_.schedule_periodic_compound_packets) {
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200128 if (ready_to_send_ && !ready)
129 periodic_task_handle_.Cancel();
Danil Chapovalove3927c52018-03-06 14:33:20 +0100130
131 if (!ready_to_send_ && ready) // Restart periodic sending.
132 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
133 }
134 ready_to_send_ = ready;
135}
136
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100137void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
138 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100139 while (!packet.empty()) {
140 rtcp::CommonHeader rtcp_block;
141 if (!rtcp_block.Parse(packet.data(), packet.size()))
142 return;
143
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100144 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100145
146 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
147 packet = packet.subview(rtcp_block.packet_size());
148 }
149}
150
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200151void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100152 if (!ready_to_send_)
153 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100154 SendPeriodicCompoundPacket();
155 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100156}
157
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100158void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100159 std::vector<uint32_t> ssrcs) {
160 RTC_DCHECK_GE(bitrate_bps, 0);
161 remb_.emplace();
162 remb_->SetSsrcs(std::move(ssrcs));
163 remb_->SetBitrateBps(bitrate_bps);
164 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
165 // immideately on large bitrate change when there is one RtcpTransceiver per
166 // rtp transport.
167}
168
169void RtcpTransceiverImpl::UnsetRemb() {
170 remb_.reset();
171}
172
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100173void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100174 if (!ready_to_send_)
175 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100176 // Unlike other senders, this functions just tries to send packet away and
177 // disregard rtcp_mode, max_packet_size or anything else.
178 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
179 // TransportFeedback inside this class when there is one per rtp transport.
180 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
181}
182
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100183void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
184 std::vector<uint16_t> sequence_numbers) {
185 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100186 if (!ready_to_send_)
187 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100188 rtcp::Nack nack;
189 nack.SetSenderSsrc(config_.feedback_ssrc);
190 nack.SetMediaSsrc(ssrc);
191 nack.SetPacketIds(std::move(sequence_numbers));
192 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100193}
194
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100195void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100196 if (!ready_to_send_)
197 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100198 rtcp::Pli pli;
199 pli.SetSenderSsrc(config_.feedback_ssrc);
200 pli.SetMediaSsrc(ssrc);
201 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100202}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100203
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100204void RtcpTransceiverImpl::SendFullIntraRequest(
205 rtc::ArrayView<const uint32_t> ssrcs) {
206 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100207 if (!ready_to_send_)
208 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100209 rtcp::Fir fir;
210 fir.SetSenderSsrc(config_.feedback_ssrc);
211 for (uint32_t media_ssrc : ssrcs)
212 fir.AddRequestTo(media_ssrc,
213 remote_senders_[media_ssrc].fir_sequence_number++);
214 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100215}
216
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100217void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100218 const rtcp::CommonHeader& rtcp_packet_header,
219 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100220 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100221 case rtcp::Bye::kPacketType:
222 HandleBye(rtcp_packet_header);
223 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100224 case rtcp::SenderReport::kPacketType:
225 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100226 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100227 case rtcp::ExtendedReports::kPacketType:
228 HandleExtendedReports(rtcp_packet_header, now_us);
229 break;
230 }
231}
232
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100233void RtcpTransceiverImpl::HandleBye(
234 const rtcp::CommonHeader& rtcp_packet_header) {
235 rtcp::Bye bye;
236 if (!bye.Parse(rtcp_packet_header))
237 return;
238 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
239 if (remote_sender_it == remote_senders_.end())
240 return;
241 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
242 observer->OnBye(bye.sender_ssrc());
243}
244
Danil Chapovalov319a6752017-11-30 14:56:52 +0100245void RtcpTransceiverImpl::HandleSenderReport(
246 const rtcp::CommonHeader& rtcp_packet_header,
247 int64_t now_us) {
248 rtcp::SenderReport sender_report;
249 if (!sender_report.Parse(rtcp_packet_header))
250 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100251 RemoteSenderState& remote_sender =
252 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalovd264df52018-06-14 12:59:38 +0200253 absl::optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100254 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100255 last.emplace();
256 last->local_received_time_us = now_us;
257 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100258
259 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
260 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
261 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100262}
263
264void RtcpTransceiverImpl::HandleExtendedReports(
265 const rtcp::CommonHeader& rtcp_packet_header,
266 int64_t now_us) {
267 rtcp::ExtendedReports extended_reports;
268 if (!extended_reports.Parse(rtcp_packet_header))
269 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100270
271 if (extended_reports.dlrr())
272 HandleDlrr(extended_reports.dlrr(), now_us);
273
274 if (extended_reports.target_bitrate())
275 HandleTargetBitrate(*extended_reports.target_bitrate(),
276 extended_reports.sender_ssrc());
277}
278
279void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
280 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
281 return;
282
283 // Delay and last_rr are transferred using 32bit compact ntp resolution.
284 // Convert packet arrival time to same format through 64bit ntp format.
285 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
286 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
287 if (rti.ssrc != config_.feedback_ssrc)
288 continue;
289 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
290 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
291 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100292 }
293}
294
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100295void RtcpTransceiverImpl::HandleTargetBitrate(
296 const rtcp::TargetBitrate& target_bitrate,
297 uint32_t remote_ssrc) {
298 auto remote_sender_it = remote_senders_.find(remote_ssrc);
299 if (remote_sender_it == remote_senders_.end() ||
300 remote_sender_it->second.observers.empty())
301 return;
302
Erik Språng566124a2018-04-23 12:32:22 +0200303 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
304 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100305 for (const rtcp::TargetBitrate::BitrateItem& item :
306 target_bitrate.GetTargetBitrates()) {
307 if (item.spatial_layer >= kMaxSpatialLayers ||
308 item.temporal_layer >= kMaxTemporalStreams) {
309 RTC_DLOG(LS_WARNING)
310 << config_.debug_id
311 << "Invalid incoming TargetBitrate with spatial layer "
312 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
313 continue;
314 }
315 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
316 item.target_bitrate_kbps * 1000);
317 }
318
319 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
320 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
321}
322
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100323void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
324 if (!config_.schedule_periodic_compound_packets)
325 return;
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200326 periodic_task_handle_.Cancel();
327 RTC_DCHECK(ready_to_send_);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100328 SchedulePeriodicCompoundPackets(config_.report_period_ms);
329}
330
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100331void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200332 auto task = rtc::CreateCancelablePeriodicTask([this] {
333 RTC_DCHECK(config_.schedule_periodic_compound_packets);
334 RTC_DCHECK(ready_to_send_);
335 SendPeriodicCompoundPacket();
336 return config_.report_period_ms;
337 });
338 periodic_task_handle_ = task->GetCancellationHandle();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100339
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100340 if (delay_ms > 0)
341 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
342 else
343 config_.task_queue->PostTask(std::move(task));
344}
345
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100346void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
347 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100348 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100349 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100350 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100351 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100352 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100353 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100354
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200355 if (!config_.cname.empty()) {
356 rtcp::Sdes sdes;
357 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
358 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
359 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100360 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200361 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100362 if (remb_) {
363 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100364 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100365 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100366 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
367 // SenderReport instead of ReceiverReport
368 // when RtcpTransceiver supports rtp senders.
369 if (config_.non_sender_rtt_measurement) {
370 rtcp::ExtendedReports xr;
371
372 rtcp::Rrtr rrtr;
373 rrtr.SetNtp(TimeMicrosToNtp(now_us));
374 xr.SetRrtr(rrtr);
375
376 xr.SetSenderSsrc(sender_ssrc);
377 sender->AppendPacket(xr);
378 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100379}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200380
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100381void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100382 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
383 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
384 };
385 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100386 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200387 sender.Send();
388}
389
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100390void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100391 const rtcp::RtcpPacket& rtcp_packet) {
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 Chapovalov8d19e032017-11-28 19:53:33 +0100396 // Compound mode requires every sent rtcp packet to be compound, i.e. start
397 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100398 if (config_.rtcp_mode == RtcpMode::kCompound)
399 CreateCompoundPacket(&sender);
400
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100401 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100402 sender.Send();
403
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100404 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100405 if (config_.rtcp_mode == RtcpMode::kCompound)
406 ReschedulePeriodicCompoundPackets();
407}
408
Danil Chapovalov319a6752017-11-30 14:56:52 +0100409std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
410 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100411 if (!config_.receive_statistics)
412 return {};
413 // TODO(danilchap): Support sending more than
414 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
415 std::vector<rtcp::ReportBlock> report_blocks =
416 config_.receive_statistics->RtcpReportBlocks(
417 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100418 uint32_t last_sr = 0;
419 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100420 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100421 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100422 if (it == remote_senders_.end() ||
423 !it->second.last_received_sender_report) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100424 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100425 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100426 const SenderReportTimes& last_sender_report =
427 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100428 last_sr = CompactNtp(last_sender_report.remote_sent_time);
429 last_delay = SaturatedUsToCompactNtp(
430 now_us - last_sender_report.local_received_time_us);
431 report_block.SetLastSr(last_sr);
432 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100433 }
434 return report_blocks;
435}
436
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200437} // namespace webrtc