blob: a4da63a10f0879d25d76493b73c96302736f04a6 [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"
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010035#include "rtc_base/timeutils.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020036
37namespace webrtc {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010038namespace {
39
40struct SenderReportTimes {
41 int64_t local_received_time_us;
42 NtpTime remote_sent_time;
43};
44
45} // namespace
46
47struct RtcpTransceiverImpl::RemoteSenderState {
48 uint8_t fir_sequence_number = 0;
Danil Chapovalovd264df52018-06-14 12:59:38 +020049 absl::optional<SenderReportTimes> last_received_sender_report;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +010050 std::vector<MediaReceiverRtcpObserver*> observers;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010051};
Danil Chapovalov398a7c62017-10-24 17:07:05 +020052
53// Helper to put several RTCP packets into lower layer datagram composing
54// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
Danil Chapovalova7e418c2017-11-21 11:08:53 +010055// TODO(danilchap): When in compound mode and packets are so many that several
56// compound RTCP packets need to be generated, ensure each packet is compound.
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010057class RtcpTransceiverImpl::PacketSender {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020058 public:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010059 PacketSender(rtcp::RtcpPacket::PacketReadyCallback callback,
60 size_t max_packet_size)
61 : callback_(callback), max_packet_size_(max_packet_size) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020062 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
63 }
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010064 ~PacketSender() { RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020065
66 // Appends a packet to pending compound packet.
67 // Sends rtcp compound packet if buffer was already full and resets buffer.
68 void AppendPacket(const rtcp::RtcpPacket& packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010069 packet.Create(buffer_, &index_, max_packet_size_, callback_);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020070 }
71
72 // Sends pending rtcp compound packet.
73 void Send() {
74 if (index_ > 0) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010075 callback_(rtc::ArrayView<const uint8_t>(buffer_, index_));
Danil Chapovalov398a7c62017-10-24 17:07:05 +020076 index_ = 0;
77 }
78 }
79
Danil Chapovalova7e418c2017-11-21 11:08:53 +010080 bool IsEmpty() const { return index_ == 0; }
81
Danil Chapovalov398a7c62017-10-24 17:07:05 +020082 private:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010083 const rtcp::RtcpPacket::PacketReadyCallback callback_;
Danil Chapovalov398a7c62017-10-24 17:07:05 +020084 const size_t max_packet_size_;
85 size_t index_ = 0;
86 uint8_t buffer_[IP_PACKET_SIZE];
87};
88
Danil Chapovalov398a7c62017-10-24 17:07:05 +020089RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalove3927c52018-03-06 14:33:20 +010090 : config_(config),
91 ready_to_send_(config.initial_ready_to_send),
92 ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020093 RTC_CHECK(config_.Validate());
Danil Chapovalove3927c52018-03-06 14:33:20 +010094 if (ready_to_send_ && config_.schedule_periodic_compound_packets)
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010095 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020096}
97
98RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
99
Danil Chapovalova32d7102017-12-14 17:28:27 +0100100void RtcpTransceiverImpl::AddMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100101 uint32_t remote_ssrc,
102 MediaReceiverRtcpObserver* observer) {
103 auto& stored = remote_senders_[remote_ssrc].observers;
104 RTC_DCHECK(std::find(stored.begin(), stored.end(), observer) == stored.end());
105 stored.push_back(observer);
106}
107
Danil Chapovalova32d7102017-12-14 17:28:27 +0100108void RtcpTransceiverImpl::RemoveMediaReceiverRtcpObserver(
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100109 uint32_t remote_ssrc,
110 MediaReceiverRtcpObserver* observer) {
111 auto remote_sender_it = remote_senders_.find(remote_ssrc);
112 if (remote_sender_it == remote_senders_.end())
113 return;
114 auto& stored = remote_sender_it->second.observers;
115 auto it = std::find(stored.begin(), stored.end(), observer);
116 if (it == stored.end())
117 return;
118 stored.erase(it);
119}
120
Danil Chapovalove3927c52018-03-06 14:33:20 +0100121void RtcpTransceiverImpl::SetReadyToSend(bool ready) {
122 if (config_.schedule_periodic_compound_packets) {
123 if (ready_to_send_ && !ready) // Stop existent send task.
124 ptr_factory_.InvalidateWeakPtrs();
125
126 if (!ready_to_send_ && ready) // Restart periodic sending.
127 SchedulePeriodicCompoundPackets(config_.report_period_ms / 2);
128 }
129 ready_to_send_ = ready;
130}
131
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100132void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
133 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100134 while (!packet.empty()) {
135 rtcp::CommonHeader rtcp_block;
136 if (!rtcp_block.Parse(packet.data(), packet.size()))
137 return;
138
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100139 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100140
141 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
142 packet = packet.subview(rtcp_block.packet_size());
143 }
144}
145
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200146void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100147 if (!ready_to_send_)
148 return;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100149 SendPeriodicCompoundPacket();
150 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100151}
152
Danil Chapovalov1de4b622017-12-13 13:35:10 +0100153void RtcpTransceiverImpl::SetRemb(int64_t bitrate_bps,
Danil Chapovalovd3282292017-11-13 13:46:02 +0100154 std::vector<uint32_t> ssrcs) {
155 RTC_DCHECK_GE(bitrate_bps, 0);
156 remb_.emplace();
157 remb_->SetSsrcs(std::move(ssrcs));
158 remb_->SetBitrateBps(bitrate_bps);
159 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
160 // immideately on large bitrate change when there is one RtcpTransceiver per
161 // rtp transport.
162}
163
164void RtcpTransceiverImpl::UnsetRemb() {
165 remb_.reset();
166}
167
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100168void RtcpTransceiverImpl::SendRawPacket(rtc::ArrayView<const uint8_t> packet) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100169 if (!ready_to_send_)
170 return;
Danil Chapovalovd5cae4d2017-12-14 11:14:35 +0100171 // Unlike other senders, this functions just tries to send packet away and
172 // disregard rtcp_mode, max_packet_size or anything else.
173 // TODO(bugs.webrtc.org/8239): respect config_ by creating the
174 // TransportFeedback inside this class when there is one per rtp transport.
175 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
176}
177
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100178void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
179 std::vector<uint16_t> sequence_numbers) {
180 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100181 if (!ready_to_send_)
182 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100183 rtcp::Nack nack;
184 nack.SetSenderSsrc(config_.feedback_ssrc);
185 nack.SetMediaSsrc(ssrc);
186 nack.SetPacketIds(std::move(sequence_numbers));
187 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100188}
189
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100190void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
Danil Chapovalove3927c52018-03-06 14:33:20 +0100191 if (!ready_to_send_)
192 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100193 rtcp::Pli pli;
194 pli.SetSenderSsrc(config_.feedback_ssrc);
195 pli.SetMediaSsrc(ssrc);
196 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100197}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100198
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100199void RtcpTransceiverImpl::SendFullIntraRequest(
200 rtc::ArrayView<const uint32_t> ssrcs) {
201 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalove3927c52018-03-06 14:33:20 +0100202 if (!ready_to_send_)
203 return;
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100204 rtcp::Fir fir;
205 fir.SetSenderSsrc(config_.feedback_ssrc);
206 for (uint32_t media_ssrc : ssrcs)
207 fir.AddRequestTo(media_ssrc,
208 remote_senders_[media_ssrc].fir_sequence_number++);
209 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100210}
211
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100212void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100213 const rtcp::CommonHeader& rtcp_packet_header,
214 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100215 switch (rtcp_packet_header.type()) {
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100216 case rtcp::Bye::kPacketType:
217 HandleBye(rtcp_packet_header);
218 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100219 case rtcp::SenderReport::kPacketType:
220 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100221 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100222 case rtcp::ExtendedReports::kPacketType:
223 HandleExtendedReports(rtcp_packet_header, now_us);
224 break;
225 }
226}
227
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100228void RtcpTransceiverImpl::HandleBye(
229 const rtcp::CommonHeader& rtcp_packet_header) {
230 rtcp::Bye bye;
231 if (!bye.Parse(rtcp_packet_header))
232 return;
233 auto remote_sender_it = remote_senders_.find(bye.sender_ssrc());
234 if (remote_sender_it == remote_senders_.end())
235 return;
236 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
237 observer->OnBye(bye.sender_ssrc());
238}
239
Danil Chapovalov319a6752017-11-30 14:56:52 +0100240void RtcpTransceiverImpl::HandleSenderReport(
241 const rtcp::CommonHeader& rtcp_packet_header,
242 int64_t now_us) {
243 rtcp::SenderReport sender_report;
244 if (!sender_report.Parse(rtcp_packet_header))
245 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100246 RemoteSenderState& remote_sender =
247 remote_senders_[sender_report.sender_ssrc()];
Danil Chapovalovd264df52018-06-14 12:59:38 +0200248 absl::optional<SenderReportTimes>& last =
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100249 remote_sender.last_received_sender_report;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100250 last.emplace();
251 last->local_received_time_us = now_us;
252 last->remote_sent_time = sender_report.ntp();
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100253
254 for (MediaReceiverRtcpObserver* observer : remote_sender.observers)
255 observer->OnSenderReport(sender_report.sender_ssrc(), sender_report.ntp(),
256 sender_report.rtp_timestamp());
Danil Chapovalov319a6752017-11-30 14:56:52 +0100257}
258
259void RtcpTransceiverImpl::HandleExtendedReports(
260 const rtcp::CommonHeader& rtcp_packet_header,
261 int64_t now_us) {
262 rtcp::ExtendedReports extended_reports;
263 if (!extended_reports.Parse(rtcp_packet_header))
264 return;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100265
266 if (extended_reports.dlrr())
267 HandleDlrr(extended_reports.dlrr(), now_us);
268
269 if (extended_reports.target_bitrate())
270 HandleTargetBitrate(*extended_reports.target_bitrate(),
271 extended_reports.sender_ssrc());
272}
273
274void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, int64_t now_us) {
275 if (!config_.non_sender_rtt_measurement || config_.rtt_observer == nullptr)
276 return;
277
278 // Delay and last_rr are transferred using 32bit compact ntp resolution.
279 // Convert packet arrival time to same format through 64bit ntp format.
280 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
281 for (const rtcp::ReceiveTimeInfo& rti : dlrr.sub_blocks()) {
282 if (rti.ssrc != config_.feedback_ssrc)
283 continue;
284 uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
285 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
286 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100287 }
288}
289
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100290void RtcpTransceiverImpl::HandleTargetBitrate(
291 const rtcp::TargetBitrate& target_bitrate,
292 uint32_t remote_ssrc) {
293 auto remote_sender_it = remote_senders_.find(remote_ssrc);
294 if (remote_sender_it == remote_senders_.end() ||
295 remote_sender_it->second.observers.empty())
296 return;
297
Erik Språng566124a2018-04-23 12:32:22 +0200298 // Convert rtcp::TargetBitrate to VideoBitrateAllocation.
299 VideoBitrateAllocation bitrate_allocation;
Danil Chapovalov7ca9ae22017-12-13 12:26:17 +0100300 for (const rtcp::TargetBitrate::BitrateItem& item :
301 target_bitrate.GetTargetBitrates()) {
302 if (item.spatial_layer >= kMaxSpatialLayers ||
303 item.temporal_layer >= kMaxTemporalStreams) {
304 RTC_DLOG(LS_WARNING)
305 << config_.debug_id
306 << "Invalid incoming TargetBitrate with spatial layer "
307 << item.spatial_layer << ", temporal layer " << item.temporal_layer;
308 continue;
309 }
310 bitrate_allocation.SetBitrate(item.spatial_layer, item.temporal_layer,
311 item.target_bitrate_kbps * 1000);
312 }
313
314 for (MediaReceiverRtcpObserver* observer : remote_sender_it->second.observers)
315 observer->OnBitrateAllocation(remote_ssrc, bitrate_allocation);
316}
317
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100318void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
319 if (!config_.schedule_periodic_compound_packets)
320 return;
321 // Stop existent send task.
322 ptr_factory_.InvalidateWeakPtrs();
323 SchedulePeriodicCompoundPackets(config_.report_period_ms);
324}
325
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100326void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100327 class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100328 public:
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100329 SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
330 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100331 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
332 bool Run() override {
333 RTC_DCHECK(task_queue_->IsCurrent());
334 if (!ptr_)
335 return true;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100336 ptr_->SendPeriodicCompoundPacket();
Karl Wiberg918f50c2018-07-05 11:40:33 +0200337 task_queue_->PostDelayedTask(absl::WrapUnique(this),
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100338 ptr_->config_.report_period_ms);
339 return false;
340 }
341
342 private:
343 rtc::TaskQueue* const task_queue_;
344 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
345 };
346
347 RTC_DCHECK(config_.schedule_periodic_compound_packets);
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100348
Karl Wiberg918f50c2018-07-05 11:40:33 +0200349 auto task = absl::make_unique<SendPeriodicCompoundPacketTask>(
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100350 config_.task_queue, ptr_factory_.GetWeakPtr());
351 if (delay_ms > 0)
352 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
353 else
354 config_.task_queue->PostTask(std::move(task));
355}
356
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100357void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
358 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100359 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100360 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100361 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100362 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100363 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100364 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100365
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200366 if (!config_.cname.empty()) {
367 rtcp::Sdes sdes;
368 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
369 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
370 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100371 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200372 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100373 if (remb_) {
374 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100375 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100376 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100377 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
378 // SenderReport instead of ReceiverReport
379 // when RtcpTransceiver supports rtp senders.
380 if (config_.non_sender_rtt_measurement) {
381 rtcp::ExtendedReports xr;
382
383 rtcp::Rrtr rrtr;
384 rrtr.SetNtp(TimeMicrosToNtp(now_us));
385 xr.SetRrtr(rrtr);
386
387 xr.SetSenderSsrc(sender_ssrc);
388 sender->AppendPacket(xr);
389 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100390}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200391
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100392void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100393 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
394 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
395 };
396 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100397 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200398 sender.Send();
399}
400
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100401void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100402 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100403 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
404 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
405 };
406 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100407 // Compound mode requires every sent rtcp packet to be compound, i.e. start
408 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100409 if (config_.rtcp_mode == RtcpMode::kCompound)
410 CreateCompoundPacket(&sender);
411
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100412 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100413 sender.Send();
414
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100415 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100416 if (config_.rtcp_mode == RtcpMode::kCompound)
417 ReschedulePeriodicCompoundPackets();
418}
419
Danil Chapovalov319a6752017-11-30 14:56:52 +0100420std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
421 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100422 if (!config_.receive_statistics)
423 return {};
424 // TODO(danilchap): Support sending more than
425 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
426 std::vector<rtcp::ReportBlock> report_blocks =
427 config_.receive_statistics->RtcpReportBlocks(
428 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
Danil Chapovalov49456a52018-01-30 09:56:23 +0100429 uint32_t last_sr = 0;
430 uint32_t last_delay = 0;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100431 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100432 auto it = remote_senders_.find(report_block.source_ssrc());
Danil Chapovalov49456a52018-01-30 09:56:23 +0100433 if (it == remote_senders_.end() ||
434 !it->second.last_received_sender_report) {
435 if (config_.avoid_zero_last_sr_in_last_report_block && last_sr != 0) {
436 // Simulate behaviour of the RtcpSender to avoid hitting bug in
437 // RtcpReceiver.
438 report_block.SetLastSr(last_sr);
439 report_block.SetDelayLastSr(last_delay);
440 }
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100441 continue;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100442 }
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100443 const SenderReportTimes& last_sender_report =
444 *it->second.last_received_sender_report;
Danil Chapovalov49456a52018-01-30 09:56:23 +0100445 last_sr = CompactNtp(last_sender_report.remote_sent_time);
446 last_delay = SaturatedUsToCompactNtp(
447 now_us - last_sender_report.local_received_time_us);
448 report_block.SetLastSr(last_sr);
449 report_block.SetDelayLastSr(last_delay);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100450 }
451 return report_blocks;
452}
453
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200454} // namespace webrtc