blob: 5378b2d3eff9c4596798c4ad06420f03f7e2af00 [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
15#include "api/call/transport.h"
16#include "modules/rtp_rtcp/include/receive_statistics.h"
17#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
18#include "modules/rtp_rtcp/source/rtcp_packet.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010019#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
Danil Chapovalov319a6752017-11-30 14:56:52 +010020#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010021#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
Danil Chapovalov327c43c2017-11-27 17:23:04 +010022#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
Danil Chapovalova7e418c2017-11-21 11:08:53 +010023#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020024#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
25#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Danil Chapovalov78161ca2017-10-26 12:09:41 +020026#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010027#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
28#include "modules/rtp_rtcp/source/time_util.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020029#include "rtc_base/checks.h"
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010030#include "rtc_base/ptr_util.h"
31#include "rtc_base/task_queue.h"
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010032#include "rtc_base/timeutils.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020033
34namespace webrtc {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +010035namespace {
36
37struct SenderReportTimes {
38 int64_t local_received_time_us;
39 NtpTime remote_sent_time;
40};
41
42} // namespace
43
44struct RtcpTransceiverImpl::RemoteSenderState {
45 uint8_t fir_sequence_number = 0;
46 rtc::Optional<SenderReportTimes> last_received_sender_report;
47};
Danil Chapovalov398a7c62017-10-24 17:07:05 +020048
49// Helper to put several RTCP packets into lower layer datagram composing
50// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
Danil Chapovalova7e418c2017-11-21 11:08:53 +010051// TODO(danilchap): When in compound mode and packets are so many that several
52// compound RTCP packets need to be generated, ensure each packet is compound.
53class RtcpTransceiverImpl::PacketSender
54 : public rtcp::RtcpPacket::PacketReadyCallback {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020055 public:
56 PacketSender(Transport* transport, size_t max_packet_size)
57 : transport_(transport), max_packet_size_(max_packet_size) {
58 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
59 }
60 ~PacketSender() override {
61 RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet.";
62 }
63
64 // Appends a packet to pending compound packet.
65 // Sends rtcp compound packet if buffer was already full and resets buffer.
66 void AppendPacket(const rtcp::RtcpPacket& packet) {
67 packet.Create(buffer_, &index_, max_packet_size_, this);
68 }
69
70 // Sends pending rtcp compound packet.
71 void Send() {
72 if (index_ > 0) {
73 OnPacketReady(buffer_, index_);
74 index_ = 0;
75 }
76 }
77
Danil Chapovalova7e418c2017-11-21 11:08:53 +010078 bool IsEmpty() const { return index_ == 0; }
79
Danil Chapovalov398a7c62017-10-24 17:07:05 +020080 private:
81 // Implements RtcpPacket::PacketReadyCallback
82 void OnPacketReady(uint8_t* data, size_t length) override {
83 transport_->SendRtcp(data, length);
84 }
85
86 Transport* const transport_;
87 const size_t max_packet_size_;
88 size_t index_ = 0;
89 uint8_t buffer_[IP_PACKET_SIZE];
90};
91
Danil Chapovalov398a7c62017-10-24 17:07:05 +020092RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010093 : config_(config), ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020094 RTC_CHECK(config_.Validate());
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010095 if (config_.schedule_periodic_compound_packets)
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010096 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020097}
98
99RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
100
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100101void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
102 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100103 while (!packet.empty()) {
104 rtcp::CommonHeader rtcp_block;
105 if (!rtcp_block.Parse(packet.data(), packet.size()))
106 return;
107
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100108 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100109
110 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
111 packet = packet.subview(rtcp_block.packet_size());
112 }
113}
114
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200115void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100116 SendPeriodicCompoundPacket();
117 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100118}
119
Danil Chapovalovd3282292017-11-13 13:46:02 +0100120void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
121 std::vector<uint32_t> ssrcs) {
122 RTC_DCHECK_GE(bitrate_bps, 0);
123 remb_.emplace();
124 remb_->SetSsrcs(std::move(ssrcs));
125 remb_->SetBitrateBps(bitrate_bps);
126 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
127 // immideately on large bitrate change when there is one RtcpTransceiver per
128 // rtp transport.
129}
130
131void RtcpTransceiverImpl::UnsetRemb() {
132 remb_.reset();
133}
134
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100135void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
136 std::vector<uint16_t> sequence_numbers) {
137 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100138 rtcp::Nack nack;
139 nack.SetSenderSsrc(config_.feedback_ssrc);
140 nack.SetMediaSsrc(ssrc);
141 nack.SetPacketIds(std::move(sequence_numbers));
142 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100143}
144
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100145void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
146 rtcp::Pli pli;
147 pli.SetSenderSsrc(config_.feedback_ssrc);
148 pli.SetMediaSsrc(ssrc);
149 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100150}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100151
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100152void RtcpTransceiverImpl::SendFullIntraRequest(
153 rtc::ArrayView<const uint32_t> ssrcs) {
154 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100155 rtcp::Fir fir;
156 fir.SetSenderSsrc(config_.feedback_ssrc);
157 for (uint32_t media_ssrc : ssrcs)
158 fir.AddRequestTo(media_ssrc,
159 remote_senders_[media_ssrc].fir_sequence_number++);
160 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100161}
162
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100163void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100164 const rtcp::CommonHeader& rtcp_packet_header,
165 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100166 switch (rtcp_packet_header.type()) {
Danil Chapovalov319a6752017-11-30 14:56:52 +0100167 case rtcp::SenderReport::kPacketType:
168 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100169 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100170 case rtcp::ExtendedReports::kPacketType:
171 HandleExtendedReports(rtcp_packet_header, now_us);
172 break;
173 }
174}
175
176void RtcpTransceiverImpl::HandleSenderReport(
177 const rtcp::CommonHeader& rtcp_packet_header,
178 int64_t now_us) {
179 rtcp::SenderReport sender_report;
180 if (!sender_report.Parse(rtcp_packet_header))
181 return;
182 rtc::Optional<SenderReportTimes>& last =
183 remote_senders_[sender_report.sender_ssrc()].last_received_sender_report;
184 last.emplace();
185 last->local_received_time_us = now_us;
186 last->remote_sent_time = sender_report.ntp();
187}
188
189void RtcpTransceiverImpl::HandleExtendedReports(
190 const rtcp::CommonHeader& rtcp_packet_header,
191 int64_t now_us) {
192 rtcp::ExtendedReports extended_reports;
193 if (!extended_reports.Parse(rtcp_packet_header))
194 return;
195 if (extended_reports.dlrr() && config_.non_sender_rtt_measurement &&
196 config_.rtt_observer) {
197 // Delay and last_rr are transferred using 32bit compact ntp resolution.
198 // Convert packet arrival time to same format through 64bit ntp format.
199 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
200 for (const rtcp::ReceiveTimeInfo& rti :
201 extended_reports.dlrr().sub_blocks()) {
202 if (rti.ssrc != config_.feedback_ssrc)
203 continue;
204 uint32_t rtt_ntp =
205 receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
206 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
207 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100208 }
209 }
210}
211
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100212void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
213 if (!config_.schedule_periodic_compound_packets)
214 return;
215 // Stop existent send task.
216 ptr_factory_.InvalidateWeakPtrs();
217 SchedulePeriodicCompoundPackets(config_.report_period_ms);
218}
219
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100220void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100221 class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100222 public:
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100223 SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
224 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100225 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
226 bool Run() override {
227 RTC_DCHECK(task_queue_->IsCurrent());
228 if (!ptr_)
229 return true;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100230 ptr_->SendPeriodicCompoundPacket();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100231 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
232 ptr_->config_.report_period_ms);
233 return false;
234 }
235
236 private:
237 rtc::TaskQueue* const task_queue_;
238 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
239 };
240
241 RTC_DCHECK(config_.schedule_periodic_compound_packets);
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100242
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100243 auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100244 config_.task_queue, ptr_factory_.GetWeakPtr());
245 if (delay_ms > 0)
246 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
247 else
248 config_.task_queue->PostTask(std::move(task));
249}
250
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100251void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
252 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100253 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100254 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100255 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100256 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100257 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100258 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100259
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200260 if (!config_.cname.empty()) {
261 rtcp::Sdes sdes;
262 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
263 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
264 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100265 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200266 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100267 if (remb_) {
268 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100269 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100270 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100271 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
272 // SenderReport instead of ReceiverReport
273 // when RtcpTransceiver supports rtp senders.
274 if (config_.non_sender_rtt_measurement) {
275 rtcp::ExtendedReports xr;
276
277 rtcp::Rrtr rrtr;
278 rrtr.SetNtp(TimeMicrosToNtp(now_us));
279 xr.SetRrtr(rrtr);
280
281 xr.SetSenderSsrc(sender_ssrc);
282 sender->AppendPacket(xr);
283 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100284}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200285
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100286void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
287 PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
288 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200289 sender.Send();
290}
291
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100292void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100293 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100294 PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100295 // Compound mode requires every sent rtcp packet to be compound, i.e. start
296 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100297 if (config_.rtcp_mode == RtcpMode::kCompound)
298 CreateCompoundPacket(&sender);
299
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100300 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100301 sender.Send();
302
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100303 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100304 if (config_.rtcp_mode == RtcpMode::kCompound)
305 ReschedulePeriodicCompoundPackets();
306}
307
Danil Chapovalov319a6752017-11-30 14:56:52 +0100308std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
309 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100310 if (!config_.receive_statistics)
311 return {};
312 // TODO(danilchap): Support sending more than
313 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
314 std::vector<rtcp::ReportBlock> report_blocks =
315 config_.receive_statistics->RtcpReportBlocks(
316 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
317 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100318 auto it = remote_senders_.find(report_block.source_ssrc());
319 if (it == remote_senders_.end() || !it->second.last_received_sender_report)
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100320 continue;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100321 const SenderReportTimes& last_sender_report =
322 *it->second.last_received_sender_report;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100323 report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time));
324 report_block.SetDelayLastSr(SaturatedUsToCompactNtp(
Danil Chapovalov319a6752017-11-30 14:56:52 +0100325 now_us - last_sender_report.local_received_time_us));
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100326 }
327 return report_blocks;
328}
329
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200330} // namespace webrtc