blob: 5753ffd6924d0f7760df3d670ce258355954aecf [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"
Sebastian Janssonecb68972019-01-18 10:30:54 +010035#include "rtc_base/task_utils/repeating_task.h"
Danil Chapovalovf351cff2020-03-05 15:43:24 +010036#include "rtc_base/task_utils/to_queued_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 {
Paul Hallakfe3dd512021-05-21 18:08:04 +020043 Timestamp local_received_time;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010044 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) {
Danil Chapovalov35b21ba2021-06-16 17:43:00 +020095 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Sebastian Janssonecb68972019-01-18 10:30:54 +010096 }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020097}
98
Danil Chapovalov6318f132019-03-07 11:15:14 +010099RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200100
Danil Chapovalova32d7102017-12-14 17:28:27 +0100101void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100102 uint32_t remote_ssrc,
103 MediaReceiverRtcpObserver* observer) {
104 auto& stored = remote_senders_[remote_ssrc].observers;
Steve Anton91c26062019-03-28 10:56:11 -0700105 RTC_DCHECK(!absl::c_linear_search(stored, observer));
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100106 stored.push_back(observer);
107}
108
Danil Chapovalova32d7102017-12-14 17:28:27 +0100109void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100110 uint32_t remote_ssrc,
111 MediaReceiverRtcpObserver* observer) {
112 auto remote_sender_it = remote_senders_.find(remote_ssrc);
113 if (remote_sender_it == remote_senders_.end())
114 return;
115 auto& stored = remote_sender_it->second.observers;
Steve Anton91c26062019-03-28 10:56:11 -0700116 auto it = absl::c_find(stored, observer);
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100117 if (it == stored.end())
118 return;
119 stored.erase(it);
120}
121
Danil Chapovalove3927c52018-03-06 14:33:20 +0100122void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
123 if (config_.schedule_periodic_compound_packets) {
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200124 if (ready_to_send_ && !ready)
Sebastian Janssonecb68972019-01-18 10:30:54 +0100125 periodic_task_handle_.Stop();
Danil Chapovalove3927c52018-03-06 14:33:20 +0100126
127 if (!ready_to_send_ && ready) // Restart periodic sending.
128 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
129 }
130 ready_to_send_ = ready;
131}
132
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100133void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200134 Timestamp now) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100135 while (!packet.empty()) {
136 rtcp::CommonHeader rtcp_block;
137 if (!rtcp_block.Parse(packet.data(), packet.size()))
138 return;
139
Paul Hallakfe3dd512021-05-21 18:08:04 +0200140 HandleReceivedPacket(rtcp_block, now);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100141
142 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
143 packet = packet.subview(rtcp_block.packet_size());
144 }
145}
146
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200147void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100148 if (!ready_to_send_)
149 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100150 SendPeriodicCompoundPacket();
151 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100152}
153
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100154void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100155 std::vector<uint32_t> ssrcs) {
156 RTC_DCHECK_GE(bitrate_bps, 0);
Per Kjellanderc93595b2020-02-27 13:20:55 +0100157
158 bool send_now = config_.send_remb_on_change &&
159 (!remb_.has_value() || bitrate_bps != remb_->bitrate_bps());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100160 remb_.emplace();
161 remb_->SetSsrcs(std::move(ssrcs));
162 remb_->SetBitrateBps(bitrate_bps);
Per Kjellanderc93595b2020-02-27 13:20:55 +0100163 remb_->SetSenderSsrc(config_.feedback_ssrc);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100164 // 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.
Per Kjellanderc93595b2020-02-27 13:20:55 +0100167 if (send_now) {
168 absl::optional<rtcp::Remb> remb;
169 remb.swap(remb_);
170 SendImmediateFeedback(*remb);
171 remb.swap(remb_);
172 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100173}
174
175void RtcpTransceiverImpl::UnsetRemb() {
176 remb_.reset();
177}
178
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100179void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100180 if (!ready_to_send_)
181 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100182 // Unlike other senders, this functions just tries to send packet away and
183 // disregard rtcp_mode, max_packet_size or anything else.
184 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
185 // TransportFeedback inside this class when there is one per rtp transport.
186 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
187}
188
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100189void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
190 std::vector<uint16_t> sequence_numbers) {
191 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100192 if (!ready_to_send_)
193 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100194 rtcp::Nack nack;
195 nack.SetSenderSsrc(config_.feedback_ssrc);
196 nack.SetMediaSsrc(ssrc);
197 nack.SetPacketIds(std::move(sequence_numbers));
198 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100199}
200
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100201void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100202 if (!ready_to_send_)
203 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100204 rtcp::Pli pli;
205 pli.SetSenderSsrc(config_.feedback_ssrc);
206 pli.SetMediaSsrc(ssrc);
207 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100208}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100209
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100210void RtcpTransceiverImpl::SendFullIntraRequest(
Evan Shrubsole577b88d2019-12-04 13:50:28 +0100211 rtc::ArrayView<const uint32_t> ssrcs,
212 bool new_request) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100213 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100214 if (!ready_to_send_)
215 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100216 rtcp::Fir fir;
217 fir.SetSenderSsrc(config_.feedback_ssrc);
Evan Shrubsole577b88d2019-12-04 13:50:28 +0100218 for (uint32_t media_ssrc : ssrcs) {
219 uint8_t& command_seq_num = remote_senders_[media_ssrc].fir_sequence_number;
220 if (new_request)
221 command_seq_num += 1;
222 fir.AddRequestTo(media_ssrc, command_seq_num);
223 }
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100224 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100225}
226
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100227void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100228 const rtcp::CommonHeader& rtcp_packet_header,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200229 Timestamp now) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100230 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100231 case rtcp::Bye::kPacketType:
232 HandleBye(rtcp_packet_header);
233 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100234 case rtcp::SenderReport::kPacketType:
Paul Hallakfe3dd512021-05-21 18:08:04 +0200235 HandleSenderReport(rtcp_packet_header, now);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100236 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100237 case rtcp::ExtendedReports::kPacketType:
Paul Hallakfe3dd512021-05-21 18:08:04 +0200238 HandleExtendedReports(rtcp_packet_header, now);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100239 break;
240 }
241}
242
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100243void RtcpTransceiverImpl::HandleBye(
244 const rtcp::CommonHeader& rtcp_packet_header) {
245 rtcp::Bye bye;
246 if (!bye.Parse(rtcp_packet_header))
247 return;
248 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
249 if (remote_sender_it == remote_senders_.end())
250 return;
251 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
252 observer->OnBye(bye.sender_ssrc());
253}
254
Danil Chapovalov319a6752017-11-30 14:56:52 +0100255void RtcpTransceiverImpl::HandleSenderReport(
256 const rtcp::CommonHeader& rtcp_packet_header,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200257 Timestamp now) {
Danil Chapovalov319a6752017-11-30 14:56:52 +0100258 rtcp::SenderReport sender_report;
259 if (!sender_report.Parse(rtcp_packet_header))
260 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100261 RemoteSenderState& remote_sender =
262 remote_senders_[sender_report.sender_ssrc()];
Paul Hallakfe3dd512021-05-21 18:08:04 +0200263 remote_sender.last_received_sender_report =
264 absl::optional<SenderReportTimes>({now, sender_report.ntp()});
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100265
266 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
267 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
268 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100269}
270
271void RtcpTransceiverImpl::HandleExtendedReports(
272 const rtcp::CommonHeader& rtcp_packet_header,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200273 Timestamp now) {
Danil Chapovalov319a6752017-11-30 14:56:52 +0100274 rtcp::ExtendedReports extended_reports;
275 if (!extended_reports.Parse(rtcp_packet_header))
276 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100277
278 if (extended_reports.dlrr())
Paul Hallakfe3dd512021-05-21 18:08:04 +0200279 HandleDlrr(extended_reports.dlrr(), now);
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100280
281 if (extended_reports.target_bitrate())
282 HandleTargetBitrate(*extended_reports.target_bitrate(),
283 extended_reports.sender_ssrc());
284}
285
Paul Hallakfe3dd512021-05-21 18:08:04 +0200286void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, Timestamp now) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100287 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
288 return;
289
290 // Delay and last_rr are transferred using 32bit compact ntp resolution.
291 // Convert packet arrival time to same format through 64bit ntp format.
Paul Hallakfe3dd512021-05-21 18:08:04 +0200292 uint32_t receive_time_ntp =
293 CompactNtp(config_.clock->ConvertTimestampToNtpTime(now));
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100294 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
295 if (rti.ssrc != config_.feedback_ssrc)
296 continue;
297 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
298 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
299 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100300 }
301}
302
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100303void RtcpTransceiverImpl::HandleTargetBitrate(
304 const rtcp::TargetBitrate& target_bitrate,
305 uint32_t remote_ssrc) {
306 auto remote_sender_it = remote_senders_.find(remote_ssrc);
307 if (remote_sender_it == remote_senders_.end() ||
308 remote_sender_it->second.observers.empty())
309 return;
310
Erik Språng566124a2018-04-23 12:32:22 +0200311 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
312 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100313 for (const rtcp::TargetBitrate::BitrateItem& item :
314 target_bitrate.GetTargetBitrates()) {
315 if (item.spatial_layer >= kMaxSpatialLayers ||
316 item.temporal_layer >= kMaxTemporalStreams) {
317 RTC_DLOG(LS_WARNING)
318 << config_.debug_id
319 << "Invalid incoming TargetBitrate with spatial layer "
320 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
321 continue;
322 }
323 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
324 item.target_bitrate_kbps * 1000);
325 }
326
327 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
328 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
329}
330
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100331void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
332 if (!config_.schedule_periodic_compound_packets)
333 return;
Sebastian Janssonecb68972019-01-18 10:30:54 +0100334 periodic_task_handle_.Stop();
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200335 RTC_DCHECK(ready_to_send_);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100336 SchedulePeriodicCompoundPackets(config_.report_period_ms);
337}
338
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100339void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100340 periodic_task_handle_ = RepeatingTaskHandle::DelayedStart(
Danil Chapovalovf351cff2020-03-05 15:43:24 +0100341 config_.task_queue, TimeDelta::Millis(delay_ms), [this] {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100342 RTC_DCHECK(config_.schedule_periodic_compound_packets);
343 RTC_DCHECK(ready_to_send_);
344 SendPeriodicCompoundPacket();
Danil Chapovalov55284022020-02-07 14:53:52 +0100345 return TimeDelta::Millis(config_.report_period_ms);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100346 });
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100347}
348
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100349void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
350 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100351 const uint32_t sender_ssrc = config_.feedback_ssrc;
Paul Hallakfe3dd512021-05-21 18:08:04 +0200352 Timestamp now = config_.clock->CurrentTime();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100353 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100354 receiver_report.SetSenderSsrc(sender_ssrc);
Paul Hallakfe3dd512021-05-21 18:08:04 +0200355 receiver_report.SetReportBlocks(CreateReportBlocks(now));
Danil Chapovalovbe530492021-06-15 11:47:16 +0000356 if (config_.rtcp_mode == RtcpMode::kCompound ||
357 !receiver_report.report_blocks().empty()) {
358 sender->AppendPacket(receiver_report);
359 }
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100360
Danil Chapovalovbe530492021-06-15 11:47:16 +0000361 if (!config_.cname.empty() && !sender->IsEmpty()) {
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200362 rtcp::Sdes sdes;
363 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
364 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
365 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100366 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200367 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100368 if (remb_) {
369 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100370 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100371 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100372 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
373 // SenderReport instead of ReceiverReport
374 // when RtcpTransceiver supports rtp senders.
375 if (config_.non_sender_rtt_measurement) {
376 rtcp::ExtendedReports xr;
377
378 rtcp::Rrtr rrtr;
Paul Hallakfe3dd512021-05-21 18:08:04 +0200379 rrtr.SetNtp(config_.clock->ConvertTimestampToNtpTime(now));
Danil Chapovalov319a6752017-11-30 14:56:52 +0100380 xr.SetRrtr(rrtr);
381
382 xr.SetSenderSsrc(sender_ssrc);
383 sender->AppendPacket(xr);
384 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100385}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200386
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100387void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100388 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
389 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
390 };
391 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100392 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200393 sender.Send();
394}
395
Per Kjellander16999812019-10-10 12:57:28 +0200396void RtcpTransceiverImpl::SendCombinedRtcpPacket(
397 std::vector<std::unique_ptr<rtcp::RtcpPacket>> rtcp_packets) {
398 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
399 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
400 };
401 PacketSender sender(send_packet, config_.max_packet_size);
402
403 for (auto& rtcp_packet : rtcp_packets) {
404 rtcp_packet->SetSenderSsrc(config_.feedback_ssrc);
405 sender.AppendPacket(*rtcp_packet);
406 }
407 sender.Send();
408}
409
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100410void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100411 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100412 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
413 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
414 };
415 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100416 // Compound mode requires every sent rtcp packet to be compound, i.e. start
417 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100418 if (config_.rtcp_mode == RtcpMode::kCompound)
419 CreateCompoundPacket(&sender);
420
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100421 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100422 sender.Send();
423
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100424 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100425 if (config_.rtcp_mode == RtcpMode::kCompound)
426 ReschedulePeriodicCompoundPackets();
427}
428
Danil Chapovalov319a6752017-11-30 14:56:52 +0100429std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
Paul Hallakfe3dd512021-05-21 18:08:04 +0200430 Timestamp now) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100431 if (!config_.receive_statistics)
432 return {};
433 // TODO(danilchap): Support sending more than
434 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
435 std::vector<rtcp::ReportBlock> report_blocks =
436 config_.receive_statistics->RtcpReportBlocks(
437 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100438 uint32_t last_sr = 0;
439 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100440 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100441 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100442 if (it == remote_senders_.end() ||
443 !it->second.last_received_sender_report) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100444 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100445 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100446 const SenderReportTimes& last_sender_report =
447 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100448 last_sr = CompactNtp(last_sender_report.remote_sent_time);
449 last_delay = SaturatedUsToCompactNtp(
Paul Hallakfe3dd512021-05-21 18:08:04 +0200450 now.us() - last_sender_report.local_received_time.us());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100451 report_block.SetLastSr(last_sr);
452 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100453 }
454 return report_blocks;
455}
456
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200457} // namespace webrtc