blob: df67c07327080b25553e62b1e938caad5e1f1eab [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 Chapovalovf351cff2020-03-05 15:43:24 +010095 config_.task_queue->PostTask(ToQueuedTask([this] {
Sebastian Janssonecb68972019-01-18 10:30:54 +010096 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalovf351cff2020-03-05 15:43:24 +010097 }));
Sebastian Janssonecb68972019-01-18 10:30:54 +010098 }
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,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200136 Timestamp now) {
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
Paul Hallakfe3dd512021-05-21 18:08:04 +0200142 HandleReceivedPacket(rtcp_block, now);
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);
Per Kjellanderc93595b2020-02-27 13:20:55 +0100159
160 bool send_now = config_.send_remb_on_change &&
161 (!remb_.has_value() || bitrate_bps != remb_->bitrate_bps());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100162 remb_.emplace();
163 remb_->SetSsrcs(std::move(ssrcs));
164 remb_->SetBitrateBps(bitrate_bps);
Per Kjellanderc93595b2020-02-27 13:20:55 +0100165 remb_->SetSenderSsrc(config_.feedback_ssrc);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100166 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
167 // immideately on large bitrate change when there is one RtcpTransceiver per
168 // rtp transport.
Per Kjellanderc93595b2020-02-27 13:20:55 +0100169 if (send_now) {
170 absl::optional<rtcp::Remb> remb;
171 remb.swap(remb_);
172 SendImmediateFeedback(*remb);
173 remb.swap(remb_);
174 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100175}
176
177void RtcpTransceiverImpl::UnsetRemb() {
178 remb_.reset();
179}
180
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100181void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100182 if (!ready_to_send_)
183 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100184 // Unlike other senders, this functions just tries to send packet away and
185 // disregard rtcp_mode, max_packet_size or anything else.
186 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
187 // TransportFeedback inside this class when there is one per rtp transport.
188 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
189}
190
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100191void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
192 std::vector<uint16_t> sequence_numbers) {
193 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100194 if (!ready_to_send_)
195 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100196 rtcp::Nack nack;
197 nack.SetSenderSsrc(config_.feedback_ssrc);
198 nack.SetMediaSsrc(ssrc);
199 nack.SetPacketIds(std::move(sequence_numbers));
200 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100201}
202
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100203void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100204 if (!ready_to_send_)
205 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100206 rtcp::Pli pli;
207 pli.SetSenderSsrc(config_.feedback_ssrc);
208 pli.SetMediaSsrc(ssrc);
209 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100210}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100211
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100212void RtcpTransceiverImpl::SendFullIntraRequest(
Evan Shrubsole577b88d2019-12-04 13:50:28 +0100213 rtc::ArrayView<const uint32_t> ssrcs,
214 bool new_request) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100215 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100216 if (!ready_to_send_)
217 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100218 rtcp::Fir fir;
219 fir.SetSenderSsrc(config_.feedback_ssrc);
Evan Shrubsole577b88d2019-12-04 13:50:28 +0100220 for (uint32_t media_ssrc : ssrcs) {
221 uint8_t& command_seq_num = remote_senders_[media_ssrc].fir_sequence_number;
222 if (new_request)
223 command_seq_num += 1;
224 fir.AddRequestTo(media_ssrc, command_seq_num);
225 }
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100226 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100227}
228
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100229void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100230 const rtcp::CommonHeader& rtcp_packet_header,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200231 Timestamp now) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100232 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100233 case rtcp::Bye::kPacketType:
234 HandleBye(rtcp_packet_header);
235 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100236 case rtcp::SenderReport::kPacketType:
Paul Hallakfe3dd512021-05-21 18:08:04 +0200237 HandleSenderReport(rtcp_packet_header, now);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100238 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100239 case rtcp::ExtendedReports::kPacketType:
Paul Hallakfe3dd512021-05-21 18:08:04 +0200240 HandleExtendedReports(rtcp_packet_header, now);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100241 break;
242 }
243}
244
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100245void RtcpTransceiverImpl::HandleBye(
246 const rtcp::CommonHeader& rtcp_packet_header) {
247 rtcp::Bye bye;
248 if (!bye.Parse(rtcp_packet_header))
249 return;
250 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
251 if (remote_sender_it == remote_senders_.end())
252 return;
253 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
254 observer->OnBye(bye.sender_ssrc());
255}
256
Danil Chapovalov319a6752017-11-30 14:56:52 +0100257void RtcpTransceiverImpl::HandleSenderReport(
258 const rtcp::CommonHeader& rtcp_packet_header,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200259 Timestamp now) {
Danil Chapovalov319a6752017-11-30 14:56:52 +0100260 rtcp::SenderReport sender_report;
261 if (!sender_report.Parse(rtcp_packet_header))
262 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100263 RemoteSenderState& remote_sender =
264 remote_senders_[sender_report.sender_ssrc()];
Paul Hallakfe3dd512021-05-21 18:08:04 +0200265 remote_sender.last_received_sender_report =
266 absl::optional<SenderReportTimes>({now, sender_report.ntp()});
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100267
268 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
269 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
270 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100271}
272
273void RtcpTransceiverImpl::HandleExtendedReports(
274 const rtcp::CommonHeader& rtcp_packet_header,
Paul Hallakfe3dd512021-05-21 18:08:04 +0200275 Timestamp now) {
Danil Chapovalov319a6752017-11-30 14:56:52 +0100276 rtcp::ExtendedReports extended_reports;
277 if (!extended_reports.Parse(rtcp_packet_header))
278 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100279
280 if (extended_reports.dlrr())
Paul Hallakfe3dd512021-05-21 18:08:04 +0200281 HandleDlrr(extended_reports.dlrr(), now);
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100282
283 if (extended_reports.target_bitrate())
284 HandleTargetBitrate(*extended_reports.target_bitrate(),
285 extended_reports.sender_ssrc());
286}
287
Paul Hallakfe3dd512021-05-21 18:08:04 +0200288void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, Timestamp now) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100289 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
290 return;
291
292 // Delay and last_rr are transferred using 32bit compact ntp resolution.
293 // Convert packet arrival time to same format through 64bit ntp format.
Paul Hallakfe3dd512021-05-21 18:08:04 +0200294 uint32_t receive_time_ntp =
295 CompactNtp(config_.clock->ConvertTimestampToNtpTime(now));
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100296 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
297 if (rti.ssrc != config_.feedback_ssrc)
298 continue;
299 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
300 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
301 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100302 }
303}
304
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100305void RtcpTransceiverImpl::HandleTargetBitrate(
306 const rtcp::TargetBitrate& target_bitrate,
307 uint32_t remote_ssrc) {
308 auto remote_sender_it = remote_senders_.find(remote_ssrc);
309 if (remote_sender_it == remote_senders_.end() ||
310 remote_sender_it->second.observers.empty())
311 return;
312
Erik Språng566124a2018-04-23 12:32:22 +0200313 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
314 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100315 for (const rtcp::TargetBitrate::BitrateItem& item :
316 target_bitrate.GetTargetBitrates()) {
317 if (item.spatial_layer >= kMaxSpatialLayers ||
318 item.temporal_layer >= kMaxTemporalStreams) {
319 RTC_DLOG(LS_WARNING)
320 << config_.debug_id
321 << "Invalid incoming TargetBitrate with spatial layer "
322 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
323 continue;
324 }
325 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
326 item.target_bitrate_kbps * 1000);
327 }
328
329 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
330 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
331}
332
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100333void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
334 if (!config_.schedule_periodic_compound_packets)
335 return;
Sebastian Janssonecb68972019-01-18 10:30:54 +0100336 periodic_task_handle_.Stop();
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200337 RTC_DCHECK(ready_to_send_);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100338 SchedulePeriodicCompoundPackets(config_.report_period_ms);
339}
340
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100341void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100342 periodic_task_handle_ = RepeatingTaskHandle::DelayedStart(
Danil Chapovalovf351cff2020-03-05 15:43:24 +0100343 config_.task_queue, TimeDelta::Millis(delay_ms), [this] {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100344 RTC_DCHECK(config_.schedule_periodic_compound_packets);
345 RTC_DCHECK(ready_to_send_);
346 SendPeriodicCompoundPacket();
Danil Chapovalov55284022020-02-07 14:53:52 +0100347 return TimeDelta::Millis(config_.report_period_ms);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100348 });
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100349}
350
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100351void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
352 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100353 const uint32_t sender_ssrc = config_.feedback_ssrc;
Paul Hallakfe3dd512021-05-21 18:08:04 +0200354 Timestamp now = config_.clock->CurrentTime();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100355 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100356 receiver_report.SetSenderSsrc(sender_ssrc);
Paul Hallakfe3dd512021-05-21 18:08:04 +0200357 receiver_report.SetReportBlocks(CreateReportBlocks(now));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100358 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100359
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200360 if (!config_.cname.empty()) {
361 rtcp::Sdes sdes;
362 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
363 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
364 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100365 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200366 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100367 if (remb_) {
368 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100369 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100370 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100371 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
372 // SenderReport instead of ReceiverReport
373 // when RtcpTransceiver supports rtp senders.
374 if (config_.non_sender_rtt_measurement) {
375 rtcp::ExtendedReports xr;
376
377 rtcp::Rrtr rrtr;
Paul Hallakfe3dd512021-05-21 18:08:04 +0200378 rrtr.SetNtp(config_.clock->ConvertTimestampToNtpTime(now));
Danil Chapovalov319a6752017-11-30 14:56:52 +0100379 xr.SetRrtr(rrtr);
380
381 xr.SetSenderSsrc(sender_ssrc);
382 sender->AppendPacket(xr);
383 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100384}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200385
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100386void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100387 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
388 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
389 };
390 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100391 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200392 sender.Send();
393}
394
Per Kjellander16999812019-10-10 12:57:28 +0200395void RtcpTransceiverImpl::SendCombinedRtcpPacket(
396 std::vector<std::unique_ptr<rtcp::RtcpPacket>> rtcp_packets) {
397 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
398 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
399 };
400 PacketSender sender(send_packet, config_.max_packet_size);
401
402 for (auto& rtcp_packet : rtcp_packets) {
403 rtcp_packet->SetSenderSsrc(config_.feedback_ssrc);
404 sender.AppendPacket(*rtcp_packet);
405 }
406 sender.Send();
407}
408
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100409void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100410 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100411 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
412 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
413 };
414 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100415 // Compound mode requires every sent rtcp packet to be compound, i.e. start
416 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100417 if (config_.rtcp_mode == RtcpMode::kCompound)
418 CreateCompoundPacket(&sender);
419
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100420 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100421 sender.Send();
422
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100423 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100424 if (config_.rtcp_mode == RtcpMode::kCompound)
425 ReschedulePeriodicCompoundPackets();
426}
427
Danil Chapovalov319a6752017-11-30 14:56:52 +0100428std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
Paul Hallakfe3dd512021-05-21 18:08:04 +0200429 Timestamp now) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100430 if (!config_.receive_statistics)
431 return {};
432 // TODO(danilchap): Support sending more than
433 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
434 std::vector<rtcp::ReportBlock> report_blocks =
435 config_.receive_statistics->RtcpReportBlocks(
436 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100437 uint32_t last_sr = 0;
438 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100439 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100440 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100441 if (it == remote_senders_.end() ||
442 !it->second.last_received_sender_report) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100443 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100444 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100445 const SenderReportTimes& last_sender_report =
446 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100447 last_sr = CompactNtp(last_sender_report.remote_sent_time);
448 last_delay = SaturatedUsToCompactNtp(
Paul Hallakfe3dd512021-05-21 18:08:04 +0200449 now.us() - last_sender_report.local_received_time.us());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100450 report_block.SetLastSr(last_sr);
451 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100452 }
453 return report_blocks;
454}
455
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200456} // namespace webrtc