blob: 5d2cd6ea22c626432761c5b7aeb268b9c28fb006 [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 Chapovalov398a7c62017-10-24 17:07:05 +020032#include "rtc_base/checks.h"
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010033#include "rtc_base/logging.h"
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010034#include "rtc_base/task_queue.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010035#include "rtc_base/task_utils/repeating_task.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());
Sebastian Janssonecb68972019-01-18 10:30:54 +010093 if (ready_to_send_ && config_.schedule_periodic_compound_packets) {
94 config_.task_queue->PostTask([this] {
95 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
96 });
97 }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020098}
99
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200100RtcpTransceiverImpl::~RtcpTransceiverImpl() {
101 // If RtcpTransceiverImpl is destroyed off task queue, assume it is destroyed
102 // after TaskQueue. In that case there is no need to Cancel periodic task.
103 if (config_.task_queue == rtc::TaskQueue::Current()) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100104 periodic_task_handle_.Stop();
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200105 }
106}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200107
Danil Chapovalova32d7102017-12-14 17:28:27 +0100108void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100109 uint32_t remote_ssrc,
110 MediaReceiverRtcpObserver* observer) {
111 auto& stored = remote_senders_[remote_ssrc].observers;
112 RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
113 stored.push_back(observer);
114}
115
Danil Chapovalova32d7102017-12-14 17:28:27 +0100116void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100117 uint32_t remote_ssrc,
118 MediaReceiverRtcpObserver* observer) {
119 auto remote_sender_it = remote_senders_.find(remote_ssrc);
120 if (remote_sender_it == remote_senders_.end())
121 return;
122 auto& stored = remote_sender_it->second.observers;
123 auto it = std::find(stored.begin(), stored.end(), observer);
124 if (it == stored.end())
125 return;
126 stored.erase(it);
127}
128
Danil Chapovalove3927c52018-03-06 14:33:20 +0100129void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
130 if (config_.schedule_periodic_compound_packets) {
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200131 if (ready_to_send_ && !ready)
Sebastian Janssonecb68972019-01-18 10:30:54 +0100132 periodic_task_handle_.Stop();
Danil Chapovalove3927c52018-03-06 14:33:20 +0100133
134 if (!ready_to_send_ && ready) // Restart periodic sending.
135 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
136 }
137 ready_to_send_ = ready;
138}
139
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100140void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
141 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100142 while (!packet.empty()) {
143 rtcp::CommonHeader rtcp_block;
144 if (!rtcp_block.Parse(packet.data(), packet.size()))
145 return;
146
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100147 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100148
149 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
150 packet = packet.subview(rtcp_block.packet_size());
151 }
152}
153
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200154void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100155 if (!ready_to_send_)
156 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100157 SendPeriodicCompoundPacket();
158 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100159}
160
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100161void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100162 std::vector<uint32_t> ssrcs) {
163 RTC_DCHECK_GE(bitrate_bps, 0);
164 remb_.emplace();
165 remb_->SetSsrcs(std::move(ssrcs));
166 remb_->SetBitrateBps(bitrate_bps);
167 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
168 // immideately on large bitrate change when there is one RtcpTransceiver per
169 // rtp transport.
170}
171
172void RtcpTransceiverImpl::UnsetRemb() {
173 remb_.reset();
174}
175
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100176void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100177 if (!ready_to_send_)
178 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100179 // Unlike other senders, this functions just tries to send packet away and
180 // disregard rtcp_mode, max_packet_size or anything else.
181 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
182 // TransportFeedback inside this class when there is one per rtp transport.
183 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
184}
185
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100186void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
187 std::vector<uint16_t> sequence_numbers) {
188 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100189 if (!ready_to_send_)
190 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100191 rtcp::Nack nack;
192 nack.SetSenderSsrc(config_.feedback_ssrc);
193 nack.SetMediaSsrc(ssrc);
194 nack.SetPacketIds(std::move(sequence_numbers));
195 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100196}
197
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100198void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100199 if (!ready_to_send_)
200 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100201 rtcp::Pli pli;
202 pli.SetSenderSsrc(config_.feedback_ssrc);
203 pli.SetMediaSsrc(ssrc);
204 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100205}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100206
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100207void RtcpTransceiverImpl::SendFullIntraRequest(
208 rtc::ArrayView<const uint32_t> ssrcs) {
209 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100210 if (!ready_to_send_)
211 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100212 rtcp::Fir fir;
213 fir.SetSenderSsrc(config_.feedback_ssrc);
214 for (uint32_t media_ssrc : ssrcs)
215 fir.AddRequestTo(media_ssrc,
216 remote_senders_[media_ssrc].fir_sequence_number++);
217 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100218}
219
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100220void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100221 const rtcp::CommonHeader& rtcp_packet_header,
222 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100223 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100224 case rtcp::Bye::kPacketType:
225 HandleBye(rtcp_packet_header);
226 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100227 case rtcp::SenderReport::kPacketType:
228 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100229 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100230 case rtcp::ExtendedReports::kPacketType:
231 HandleExtendedReports(rtcp_packet_header, now_us);
232 break;
233 }
234}
235
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100236void RtcpTransceiverImpl::HandleBye(
237 const rtcp::CommonHeader& rtcp_packet_header) {
238 rtcp::Bye bye;
239 if (!bye.Parse(rtcp_packet_header))
240 return;
241 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
242 if (remote_sender_it == remote_senders_.end())
243 return;
244 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
245 observer->OnBye(bye.sender_ssrc());
246}
247
Danil Chapovalov319a6752017-11-30 14:56:52 +0100248void RtcpTransceiverImpl::HandleSenderReport(
249 const rtcp::CommonHeader& rtcp_packet_header,
250 int64_t now_us) {
251 rtcp::SenderReport sender_report;
252 if (!sender_report.Parse(rtcp_packet_header))
253 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100254 RemoteSenderState& remote_sender =
255 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalovd264df52018-06-14 12:59:38 +0200256 absl::optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100257 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100258 last.emplace();
259 last->local_received_time_us = now_us;
260 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100261
262 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
263 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
264 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100265}
266
267void RtcpTransceiverImpl::HandleExtendedReports(
268 const rtcp::CommonHeader& rtcp_packet_header,
269 int64_t now_us) {
270 rtcp::ExtendedReports extended_reports;
271 if (!extended_reports.Parse(rtcp_packet_header))
272 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100273
274 if (extended_reports.dlrr())
275 HandleDlrr(extended_reports.dlrr(), now_us);
276
277 if (extended_reports.target_bitrate())
278 HandleTargetBitrate(*extended_reports.target_bitrate(),
279 extended_reports.sender_ssrc());
280}
281
282void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
283 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
284 return;
285
286 // Delay and last_rr are transferred using 32bit compact ntp resolution.
287 // Convert packet arrival time to same format through 64bit ntp format.
288 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
289 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
290 if (rti.ssrc != config_.feedback_ssrc)
291 continue;
292 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
293 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
294 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100295 }
296}
297
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100298void RtcpTransceiverImpl::HandleTargetBitrate(
299 const rtcp::TargetBitrate& target_bitrate,
300 uint32_t remote_ssrc) {
301 auto remote_sender_it = remote_senders_.find(remote_ssrc);
302 if (remote_sender_it == remote_senders_.end() ||
303 remote_sender_it->second.observers.empty())
304 return;
305
Erik Språng566124a2018-04-23 12:32:22 +0200306 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
307 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100308 for (const rtcp::TargetBitrate::BitrateItem& item :
309 target_bitrate.GetTargetBitrates()) {
310 if (item.spatial_layer >= kMaxSpatialLayers ||
311 item.temporal_layer >= kMaxTemporalStreams) {
312 RTC_DLOG(LS_WARNING)
313 << config_.debug_id
314 << "Invalid incoming TargetBitrate with spatial layer "
315 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
316 continue;
317 }
318 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
319 item.target_bitrate_kbps * 1000);
320 }
321
322 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
323 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
324}
325
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100326void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
327 if (!config_.schedule_periodic_compound_packets)
328 return;
Sebastian Janssonecb68972019-01-18 10:30:54 +0100329 periodic_task_handle_.Stop();
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200330 RTC_DCHECK(ready_to_send_);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100331 SchedulePeriodicCompoundPackets(config_.report_period_ms);
332}
333
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100334void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100335 periodic_task_handle_ = RepeatingTaskHandle::DelayedStart(
336 config_.task_queue, TimeDelta::ms(delay_ms), [this] {
337 RTC_DCHECK(config_.schedule_periodic_compound_packets);
338 RTC_DCHECK(ready_to_send_);
339 SendPeriodicCompoundPacket();
340 return TimeDelta::ms(config_.report_period_ms);
341 });
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100342}
343
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100344void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
345 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100346 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100347 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100348 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100349 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100350 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100351 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100352
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200353 if (!config_.cname.empty()) {
354 rtcp::Sdes sdes;
355 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
356 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
357 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100358 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200359 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100360 if (remb_) {
361 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100362 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100363 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100364 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
365 // SenderReport instead of ReceiverReport
366 // when RtcpTransceiver supports rtp senders.
367 if (config_.non_sender_rtt_measurement) {
368 rtcp::ExtendedReports xr;
369
370 rtcp::Rrtr rrtr;
371 rrtr.SetNtp(TimeMicrosToNtp(now_us));
372 xr.SetRrtr(rrtr);
373
374 xr.SetSenderSsrc(sender_ssrc);
375 sender->AppendPacket(xr);
376 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100377}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200378
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100379void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100380 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
381 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
382 };
383 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100384 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200385 sender.Send();
386}
387
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100388void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100389 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100390 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
391 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
392 };
393 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100394 // Compound mode requires every sent rtcp packet to be compound, i.e. start
395 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100396 if (config_.rtcp_mode == RtcpMode::kCompound)
397 CreateCompoundPacket(&sender);
398
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100399 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100400 sender.Send();
401
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100402 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100403 if (config_.rtcp_mode == RtcpMode::kCompound)
404 ReschedulePeriodicCompoundPackets();
405}
406
Danil Chapovalov319a6752017-11-30 14:56:52 +0100407std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
408 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100409 if (!config_.receive_statistics)
410 return {};
411 // TODO(danilchap): Support sending more than
412 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
413 std::vector<rtcp::ReportBlock> report_blocks =
414 config_.receive_statistics->RtcpReportBlocks(
415 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100416 uint32_t last_sr = 0;
417 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100418 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100419 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100420 if (it == remote_senders_.end() ||
421 !it->second.last_received_sender_report) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100422 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100423 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100424 const SenderReportTimes& last_sender_report =
425 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100426 last_sr = CompactNtp(last_sender_report.remote_sent_time);
427 last_delay = SaturatedUsToCompactNtp(
428 now_us - last_sender_report.local_received_time_us);
429 report_block.SetLastSr(last_sr);
430 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100431 }
432 return report_blocks;
433}
434
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200435} // namespace webrtc