blob: 977fc8b7b79288dcf337338b69f9248627805ca8 [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
Steve Anton91c26062019-03-28 10:56:11 -070015#include "absl/algorithm/container.h"
Karl Wiberg918f50c2018-07-05 11:40:33 +020016#include "absl/memory/memory.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020017#include "api/call/transport.h"
Erik Språngeeaa8f92018-05-17 12:35:56 +020018#include "api/video/video_bitrate_allocation.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020019#include "modules/rtp_rtcp/include/receive_statistics.h"
20#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
21#include "modules/rtp_rtcp/source/rtcp_packet.h"
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010022#include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010023#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
Danil Chapovalov319a6752017-11-30 14:56:52 +010024#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010025#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
Danil Chapovalov327c43c2017-11-27 17:23:04 +010026#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
Danil Chapovalova7e418c2017-11-21 11:08:53 +010027#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020028#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
29#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Danil Chapovalov78161ca2017-10-26 12:09:41 +020030#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010031#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
32#include "modules/rtp_rtcp/source/time_util.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"
Sebastian Janssonecb68972019-01-18 10:30:54 +010036#include "rtc_base/task_utils/repeating_task.h"
Steve Anton10542f22019-01-11 09:11:00 -080037#include "rtc_base/time_utils.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020038
39namespace webrtc {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010040namespace {
41
42struct SenderReportTimes {
43 int64_t local_received_time_us;
44 NtpTime remote_sent_time;
45};
46
47} // namespace
48
49struct RtcpTransceiverImpl::RemoteSenderState {
50 uint8_t fir_sequence_number = 0;
Danil Chapovalovd264df52018-06-14 12:59:38 +020051 absl::optional<SenderReportTimes> last_received_sender_report;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010052 std::vector<MediaReceiverRtcpObserver*> observers;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010053};
Danil Chapovalov398a7c62017-10-24 17:07:05 +020054
55// Helper to put several RTCP packets into lower layer datagram composing
56// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
Danil Chapovalova7e418c2017-11-21 11:08:53 +010057// TODO(danilchap): When in compound mode and packets are so many that several
58// compound RTCP packets need to be generated, ensure each packet is compound.
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010059class RtcpTransceiverImpl::PacketSender {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020060 public:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010061 PacketSender(rtcp::RtcpPacket::PacketReadyCallback callback,
62 size_t max_packet_size)
63 : callback_(callback), max_packet_size_(max_packet_size) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020064 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
65 }
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010066 ~PacketSender() { RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020067
68 // Appends a packet to pending compound packet.
69 // Sends rtcp compound packet if buffer was already full and resets buffer.
70 void AppendPacket(const rtcp::RtcpPacket& packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010071 packet.Create(buffer_, &index_, max_packet_size_, callback_);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020072 }
73
74 // Sends pending rtcp compound packet.
75 void Send() {
76 if (index_ > 0) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010077 callback_(rtc::ArrayView<const uint8_t>(buffer_, index_));
Danil Chapovalov398a7c62017-10-24 17:07:05 +020078 index_ = 0;
79 }
80 }
81
Danil Chapovalova7e418c2017-11-21 11:08:53 +010082 bool IsEmpty() const { return index_ == 0; }
83
Danil Chapovalov398a7c62017-10-24 17:07:05 +020084 private:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010085 const rtcp::RtcpPacket::PacketReadyCallback callback_;
Danil Chapovalov398a7c62017-10-24 17:07:05 +020086 const size_t max_packet_size_;
87 size_t index_ = 0;
88 uint8_t buffer_[IP_PACKET_SIZE];
89};
90
Danil Chapovalov398a7c62017-10-24 17:07:05 +020091RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +020092 : config_(config), ready_to_send_(config.initial_ready_to_send) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020093 RTC_CHECK(config_.Validate());
Sebastian Janssonecb68972019-01-18 10:30:54 +010094 if (ready_to_send_ && config_.schedule_periodic_compound_packets) {
95 config_.task_queue->PostTask([this] {
96 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
97 });
98 }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020099}
100
Danil Chapovalov6318f132019-03-07 11:15:14 +0100101RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200102
Danil Chapovalova32d7102017-12-14 17:28:27 +0100103void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100104 uint32_t remote_ssrc,
105 MediaReceiverRtcpObserver* observer) {
106 auto& stored = remote_senders_[remote_ssrc].observers;
Steve Anton91c26062019-03-28 10:56:11 -0700107 RTC_DCHECK(!absl::c_linear_search(stored, observer));
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100108 stored.push_back(observer);
109}
110
Danil Chapovalova32d7102017-12-14 17:28:27 +0100111void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100112 uint32_t remote_ssrc,
113 MediaReceiverRtcpObserver* observer) {
114 auto remote_sender_it = remote_senders_.find(remote_ssrc);
115 if (remote_sender_it == remote_senders_.end())
116 return;
117 auto& stored = remote_sender_it->second.observers;
Steve Anton91c26062019-03-28 10:56:11 -0700118 auto it = absl::c_find(stored, observer);
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100119 if (it == stored.end())
120 return;
121 stored.erase(it);
122}
123
Danil Chapovalove3927c52018-03-06 14:33:20 +0100124void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
125 if (config_.schedule_periodic_compound_packets) {
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200126 if (ready_to_send_ && !ready)
Sebastian Janssonecb68972019-01-18 10:30:54 +0100127 periodic_task_handle_.Stop();
Danil Chapovalove3927c52018-03-06 14:33:20 +0100128
129 if (!ready_to_send_ && ready) // Restart periodic sending.
130 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
131 }
132 ready_to_send_ = ready;
133}
134
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100135void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
136 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100137 while (!packet.empty()) {
138 rtcp::CommonHeader rtcp_block;
139 if (!rtcp_block.Parse(packet.data(), packet.size()))
140 return;
141
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100142 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100143
144 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
145 packet = packet.subview(rtcp_block.packet_size());
146 }
147}
148
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200149void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100150 if (!ready_to_send_)
151 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100152 SendPeriodicCompoundPacket();
153 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100154}
155
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100156void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100157 std::vector<uint32_t> ssrcs) {
158 RTC_DCHECK_GE(bitrate_bps, 0);
159 remb_.emplace();
160 remb_->SetSsrcs(std::move(ssrcs));
161 remb_->SetBitrateBps(bitrate_bps);
162 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
163 // immideately on large bitrate change when there is one RtcpTransceiver per
164 // rtp transport.
165}
166
167void RtcpTransceiverImpl::UnsetRemb() {
168 remb_.reset();
169}
170
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100171void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100172 if (!ready_to_send_)
173 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100174 // Unlike other senders, this functions just tries to send packet away and
175 // disregard rtcp_mode, max_packet_size or anything else.
176 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
177 // TransportFeedback inside this class when there is one per rtp transport.
178 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
179}
180
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100181void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
182 std::vector<uint16_t> sequence_numbers) {
183 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100184 if (!ready_to_send_)
185 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100186 rtcp::Nack nack;
187 nack.SetSenderSsrc(config_.feedback_ssrc);
188 nack.SetMediaSsrc(ssrc);
189 nack.SetPacketIds(std::move(sequence_numbers));
190 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100191}
192
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100193void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100194 if (!ready_to_send_)
195 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100196 rtcp::Pli pli;
197 pli.SetSenderSsrc(config_.feedback_ssrc);
198 pli.SetMediaSsrc(ssrc);
199 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100200}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100201
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100202void RtcpTransceiverImpl::SendFullIntraRequest(
203 rtc::ArrayView<const uint32_t> ssrcs) {
204 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100205 if (!ready_to_send_)
206 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100207 rtcp::Fir fir;
208 fir.SetSenderSsrc(config_.feedback_ssrc);
209 for (uint32_t media_ssrc : ssrcs)
210 fir.AddRequestTo(media_ssrc,
211 remote_senders_[media_ssrc].fir_sequence_number++);
212 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100213}
214
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100215void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100216 const rtcp::CommonHeader& rtcp_packet_header,
217 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100218 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100219 case rtcp::Bye::kPacketType:
220 HandleBye(rtcp_packet_header);
221 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100222 case rtcp::SenderReport::kPacketType:
223 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100224 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100225 case rtcp::ExtendedReports::kPacketType:
226 HandleExtendedReports(rtcp_packet_header, now_us);
227 break;
228 }
229}
230
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100231void RtcpTransceiverImpl::HandleBye(
232 const rtcp::CommonHeader& rtcp_packet_header) {
233 rtcp::Bye bye;
234 if (!bye.Parse(rtcp_packet_header))
235 return;
236 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
237 if (remote_sender_it == remote_senders_.end())
238 return;
239 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
240 observer->OnBye(bye.sender_ssrc());
241}
242
Danil Chapovalov319a6752017-11-30 14:56:52 +0100243void RtcpTransceiverImpl::HandleSenderReport(
244 const rtcp::CommonHeader& rtcp_packet_header,
245 int64_t now_us) {
246 rtcp::SenderReport sender_report;
247 if (!sender_report.Parse(rtcp_packet_header))
248 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100249 RemoteSenderState& remote_sender =
250 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalovd264df52018-06-14 12:59:38 +0200251 absl::optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100252 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100253 last.emplace();
254 last->local_received_time_us = now_us;
255 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100256
257 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
258 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
259 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100260}
261
262void RtcpTransceiverImpl::HandleExtendedReports(
263 const rtcp::CommonHeader& rtcp_packet_header,
264 int64_t now_us) {
265 rtcp::ExtendedReports extended_reports;
266 if (!extended_reports.Parse(rtcp_packet_header))
267 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100268
269 if (extended_reports.dlrr())
270 HandleDlrr(extended_reports.dlrr(), now_us);
271
272 if (extended_reports.target_bitrate())
273 HandleTargetBitrate(*extended_reports.target_bitrate(),
274 extended_reports.sender_ssrc());
275}
276
277void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
278 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
279 return;
280
281 // Delay and last_rr are transferred using 32bit compact ntp resolution.
282 // Convert packet arrival time to same format through 64bit ntp format.
283 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
284 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
285 if (rti.ssrc != config_.feedback_ssrc)
286 continue;
287 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
288 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
289 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100290 }
291}
292
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100293void RtcpTransceiverImpl::HandleTargetBitrate(
294 const rtcp::TargetBitrate& target_bitrate,
295 uint32_t remote_ssrc) {
296 auto remote_sender_it = remote_senders_.find(remote_ssrc);
297 if (remote_sender_it == remote_senders_.end() ||
298 remote_sender_it->second.observers.empty())
299 return;
300
Erik Språng566124a2018-04-23 12:32:22 +0200301 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
302 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100303 for (const rtcp::TargetBitrate::BitrateItem& item :
304 target_bitrate.GetTargetBitrates()) {
305 if (item.spatial_layer >= kMaxSpatialLayers ||
306 item.temporal_layer >= kMaxTemporalStreams) {
307 RTC_DLOG(LS_WARNING)
308 << config_.debug_id
309 << "Invalid incoming TargetBitrate with spatial layer "
310 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
311 continue;
312 }
313 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
314 item.target_bitrate_kbps * 1000);
315 }
316
317 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
318 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
319}
320
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100321void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
322 if (!config_.schedule_periodic_compound_packets)
323 return;
Sebastian Janssonecb68972019-01-18 10:30:54 +0100324 periodic_task_handle_.Stop();
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200325 RTC_DCHECK(ready_to_send_);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100326 SchedulePeriodicCompoundPackets(config_.report_period_ms);
327}
328
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100329void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100330 periodic_task_handle_ = RepeatingTaskHandle::DelayedStart(
Danil Chapovalov4423c362019-03-06 18:41:39 +0100331 config_.task_queue->Get(), TimeDelta::ms(delay_ms), [this] {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100332 RTC_DCHECK(config_.schedule_periodic_compound_packets);
333 RTC_DCHECK(ready_to_send_);
334 SendPeriodicCompoundPacket();
335 return TimeDelta::ms(config_.report_period_ms);
336 });
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100337}
338
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100339void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
340 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100341 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100342 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100343 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100344 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100345 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100346 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100347
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200348 if (!config_.cname.empty()) {
349 rtcp::Sdes sdes;
350 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
351 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
352 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100353 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200354 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100355 if (remb_) {
356 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100357 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100358 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100359 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
360 // SenderReport instead of ReceiverReport
361 // when RtcpTransceiver supports rtp senders.
362 if (config_.non_sender_rtt_measurement) {
363 rtcp::ExtendedReports xr;
364
365 rtcp::Rrtr rrtr;
366 rrtr.SetNtp(TimeMicrosToNtp(now_us));
367 xr.SetRrtr(rrtr);
368
369 xr.SetSenderSsrc(sender_ssrc);
370 sender->AppendPacket(xr);
371 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100372}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200373
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100374void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100375 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
376 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
377 };
378 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100379 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200380 sender.Send();
381}
382
Per Kjellander16999812019-10-10 12:57:28 +0200383void RtcpTransceiverImpl::SendCombinedRtcpPacket(
384 std::vector<std::unique_ptr<rtcp::RtcpPacket>> rtcp_packets) {
385 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
386 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
387 };
388 PacketSender sender(send_packet, config_.max_packet_size);
389
390 for (auto& rtcp_packet : rtcp_packets) {
391 rtcp_packet->SetSenderSsrc(config_.feedback_ssrc);
392 sender.AppendPacket(*rtcp_packet);
393 }
394 sender.Send();
395}
396
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100397void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100398 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100399 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
400 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
401 };
402 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100403 // Compound mode requires every sent rtcp packet to be compound, i.e. start
404 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100405 if (config_.rtcp_mode == RtcpMode::kCompound)
406 CreateCompoundPacket(&sender);
407
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100408 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100409 sender.Send();
410
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100411 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100412 if (config_.rtcp_mode == RtcpMode::kCompound)
413 ReschedulePeriodicCompoundPackets();
414}
415
Danil Chapovalov319a6752017-11-30 14:56:52 +0100416std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
417 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100418 if (!config_.receive_statistics)
419 return {};
420 // TODO(danilchap): Support sending more than
421 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
422 std::vector<rtcp::ReportBlock> report_blocks =
423 config_.receive_statistics->RtcpReportBlocks(
424 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100425 uint32_t last_sr = 0;
426 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100427 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100428 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100429 if (it == remote_senders_.end() ||
430 !it->second.last_received_sender_report) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100431 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100432 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100433 const SenderReportTimes& last_sender_report =
434 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100435 last_sr = CompactNtp(last_sender_report.remote_sent_time);
436 last_delay = SaturatedUsToCompactNtp(
437 now_us - last_sender_report.local_received_time_us);
438 report_block.SetLastSr(last_sr);
439 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100440 }
441 return report_blocks;
442}
443
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200444} // namespace webrtc