blob: dd895ad295333d61b0939b9654ddd1336f35f6b0 [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 Chapovalov6318f132019-03-07 11:15:14 +0100100RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200101
Danil Chapovalova32d7102017-12-14 17:28:27 +0100102void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100103 uint32_t remote_ssrc,
104 MediaReceiverRtcpObserver* observer) {
105 auto& stored = remote_senders_[remote_ssrc].observers;
106 RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
107 stored.push_back(observer);
108}
109
Danil Chapovalova32d7102017-12-14 17:28:27 +0100110void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100111 uint32_t remote_ssrc,
112 MediaReceiverRtcpObserver* observer) {
113 auto remote_sender_it = remote_senders_.find(remote_ssrc);
114 if (remote_sender_it == remote_senders_.end())
115 return;
116 auto& stored = remote_sender_it->second.observers;
117 auto it = std::find(stored.begin(), stored.end(), observer);
118 if (it == stored.end())
119 return;
120 stored.erase(it);
121}
122
Danil Chapovalove3927c52018-03-06 14:33:20 +0100123void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
124 if (config_.schedule_periodic_compound_packets) {
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200125 if (ready_to_send_ && !ready)
Sebastian Janssonecb68972019-01-18 10:30:54 +0100126 periodic_task_handle_.Stop();
Danil Chapovalove3927c52018-03-06 14:33:20 +0100127
128 if (!ready_to_send_ && ready) // Restart periodic sending.
129 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
130 }
131 ready_to_send_ = ready;
132}
133
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100134void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
135 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100136 while (!packet.empty()) {
137 rtcp::CommonHeader rtcp_block;
138 if (!rtcp_block.Parse(packet.data(), packet.size()))
139 return;
140
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100141 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100142
143 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
144 packet = packet.subview(rtcp_block.packet_size());
145 }
146}
147
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200148void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100149 if (!ready_to_send_)
150 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100151 SendPeriodicCompoundPacket();
152 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100153}
154
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100155void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100156 std::vector<uint32_t> ssrcs) {
157 RTC_DCHECK_GE(bitrate_bps, 0);
158 remb_.emplace();
159 remb_->SetSsrcs(std::move(ssrcs));
160 remb_->SetBitrateBps(bitrate_bps);
161 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
162 // immideately on large bitrate change when there is one RtcpTransceiver per
163 // rtp transport.
164}
165
166void RtcpTransceiverImpl::UnsetRemb() {
167 remb_.reset();
168}
169
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100170void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100171 if (!ready_to_send_)
172 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100173 // Unlike other senders, this functions just tries to send packet away and
174 // disregard rtcp_mode, max_packet_size or anything else.
175 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
176 // TransportFeedback inside this class when there is one per rtp transport.
177 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
178}
179
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100180void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
181 std::vector<uint16_t> sequence_numbers) {
182 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100183 if (!ready_to_send_)
184 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100185 rtcp::Nack nack;
186 nack.SetSenderSsrc(config_.feedback_ssrc);
187 nack.SetMediaSsrc(ssrc);
188 nack.SetPacketIds(std::move(sequence_numbers));
189 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100190}
191
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100192void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100193 if (!ready_to_send_)
194 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100195 rtcp::Pli pli;
196 pli.SetSenderSsrc(config_.feedback_ssrc);
197 pli.SetMediaSsrc(ssrc);
198 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100199}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100200
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100201void RtcpTransceiverImpl::SendFullIntraRequest(
202 rtc::ArrayView<const uint32_t> ssrcs) {
203 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100204 if (!ready_to_send_)
205 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100206 rtcp::Fir fir;
207 fir.SetSenderSsrc(config_.feedback_ssrc);
208 for (uint32_t media_ssrc : ssrcs)
209 fir.AddRequestTo(media_ssrc,
210 remote_senders_[media_ssrc].fir_sequence_number++);
211 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100212}
213
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100214void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100215 const rtcp::CommonHeader& rtcp_packet_header,
216 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100217 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100218 case rtcp::Bye::kPacketType:
219 HandleBye(rtcp_packet_header);
220 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100221 case rtcp::SenderReport::kPacketType:
222 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100223 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100224 case rtcp::ExtendedReports::kPacketType:
225 HandleExtendedReports(rtcp_packet_header, now_us);
226 break;
227 }
228}
229
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100230void RtcpTransceiverImpl::HandleBye(
231 const rtcp::CommonHeader& rtcp_packet_header) {
232 rtcp::Bye bye;
233 if (!bye.Parse(rtcp_packet_header))
234 return;
235 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
236 if (remote_sender_it == remote_senders_.end())
237 return;
238 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
239 observer->OnBye(bye.sender_ssrc());
240}
241
Danil Chapovalov319a6752017-11-30 14:56:52 +0100242void RtcpTransceiverImpl::HandleSenderReport(
243 const rtcp::CommonHeader& rtcp_packet_header,
244 int64_t now_us) {
245 rtcp::SenderReport sender_report;
246 if (!sender_report.Parse(rtcp_packet_header))
247 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100248 RemoteSenderState& remote_sender =
249 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalovd264df52018-06-14 12:59:38 +0200250 absl::optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100251 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100252 last.emplace();
253 last->local_received_time_us = now_us;
254 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100255
256 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
257 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
258 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100259}
260
261void RtcpTransceiverImpl::HandleExtendedReports(
262 const rtcp::CommonHeader& rtcp_packet_header,
263 int64_t now_us) {
264 rtcp::ExtendedReports extended_reports;
265 if (!extended_reports.Parse(rtcp_packet_header))
266 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100267
268 if (extended_reports.dlrr())
269 HandleDlrr(extended_reports.dlrr(), now_us);
270
271 if (extended_reports.target_bitrate())
272 HandleTargetBitrate(*extended_reports.target_bitrate(),
273 extended_reports.sender_ssrc());
274}
275
276void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
277 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
278 return;
279
280 // Delay and last_rr are transferred using 32bit compact ntp resolution.
281 // Convert packet arrival time to same format through 64bit ntp format.
282 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
283 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
284 if (rti.ssrc != config_.feedback_ssrc)
285 continue;
286 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
287 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
288 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100289 }
290}
291
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100292void RtcpTransceiverImpl::HandleTargetBitrate(
293 const rtcp::TargetBitrate& target_bitrate,
294 uint32_t remote_ssrc) {
295 auto remote_sender_it = remote_senders_.find(remote_ssrc);
296 if (remote_sender_it == remote_senders_.end() ||
297 remote_sender_it->second.observers.empty())
298 return;
299
Erik Språng566124a2018-04-23 12:32:22 +0200300 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
301 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100302 for (const rtcp::TargetBitrate::BitrateItem& item :
303 target_bitrate.GetTargetBitrates()) {
304 if (item.spatial_layer >= kMaxSpatialLayers ||
305 item.temporal_layer >= kMaxTemporalStreams) {
306 RTC_DLOG(LS_WARNING)
307 << config_.debug_id
308 << "Invalid incoming TargetBitrate with spatial layer "
309 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
310 continue;
311 }
312 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
313 item.target_bitrate_kbps * 1000);
314 }
315
316 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
317 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
318}
319
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100320void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
321 if (!config_.schedule_periodic_compound_packets)
322 return;
Sebastian Janssonecb68972019-01-18 10:30:54 +0100323 periodic_task_handle_.Stop();
Danil Chapovalov1a6a4f32018-09-05 12:24:07 +0200324 RTC_DCHECK(ready_to_send_);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100325 SchedulePeriodicCompoundPackets(config_.report_period_ms);
326}
327
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100328void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100329 periodic_task_handle_ = RepeatingTaskHandle::DelayedStart(
Danil Chapovalov4423c362019-03-06 18:41:39 +0100330 config_.task_queue->Get(), TimeDelta::ms(delay_ms), [this] {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100331 RTC_DCHECK(config_.schedule_periodic_compound_packets);
332 RTC_DCHECK(ready_to_send_);
333 SendPeriodicCompoundPacket();
334 return TimeDelta::ms(config_.report_period_ms);
335 });
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100336}
337
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100338void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
339 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100340 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100341 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100342 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100343 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100344 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100345 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100346
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200347 if (!config_.cname.empty()) {
348 rtcp::Sdes sdes;
349 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
350 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
351 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100352 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200353 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100354 if (remb_) {
355 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100356 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100357 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100358 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
359 // SenderReport instead of ReceiverReport
360 // when RtcpTransceiver supports rtp senders.
361 if (config_.non_sender_rtt_measurement) {
362 rtcp::ExtendedReports xr;
363
364 rtcp::Rrtr rrtr;
365 rrtr.SetNtp(TimeMicrosToNtp(now_us));
366 xr.SetRrtr(rrtr);
367
368 xr.SetSenderSsrc(sender_ssrc);
369 sender->AppendPacket(xr);
370 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100371}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200372
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100373void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100374 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
375 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
376 };
377 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100378 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200379 sender.Send();
380}
381
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100382void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100383 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100384 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
385 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
386 };
387 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100388 // Compound mode requires every sent rtcp packet to be compound, i.e. start
389 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100390 if (config_.rtcp_mode == RtcpMode::kCompound)
391 CreateCompoundPacket(&sender);
392
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100393 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100394 sender.Send();
395
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100396 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100397 if (config_.rtcp_mode == RtcpMode::kCompound)
398 ReschedulePeriodicCompoundPackets();
399}
400
Danil Chapovalov319a6752017-11-30 14:56:52 +0100401std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
402 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100403 if (!config_.receive_statistics)
404 return {};
405 // TODO(danilchap): Support sending more than
406 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
407 std::vector<rtcp::ReportBlock> report_blocks =
408 config_.receive_statistics->RtcpReportBlocks(
409 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100410 uint32_t last_sr = 0;
411 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100412 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100413 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100414 if (it == remote_senders_.end() ||
415 !it->second.last_received_sender_report) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100416 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100417 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100418 const SenderReportTimes& last_sender_report =
419 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100420 last_sr = CompactNtp(last_sender_report.remote_sent_time);
421 last_delay = SaturatedUsToCompactNtp(
422 now_us - last_sender_report.local_received_time_us);
423 report_block.SetLastSr(last_sr);
424 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100425 }
426 return report_blocks;
427}
428
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200429} // namespace webrtc