blob: 990ca900b43550f46cd4ca44b17b7a28cb498d5f [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.
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010053class RtcpTransceiverImpl::PacketSender {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020054 public:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010055 PacketSender(rtcp::RtcpPacket::PacketReadyCallback callback,
56 size_t max_packet_size)
57 : callback_(callback), max_packet_size_(max_packet_size) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020058 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
59 }
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010060 ~PacketSender() { RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet."; }
Danil Chapovalov398a7c62017-10-24 17:07:05 +020061
62 // Appends a packet to pending compound packet.
63 // Sends rtcp compound packet if buffer was already full and resets buffer.
64 void AppendPacket(const rtcp::RtcpPacket& packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010065 packet.Create(buffer_, &index_, max_packet_size_, callback_);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020066 }
67
68 // Sends pending rtcp compound packet.
69 void Send() {
70 if (index_ > 0) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010071 callback_(rtc::ArrayView<const uint8_t>(buffer_, index_));
Danil Chapovalov398a7c62017-10-24 17:07:05 +020072 index_ = 0;
73 }
74 }
75
Danil Chapovalova7e418c2017-11-21 11:08:53 +010076 bool IsEmpty() const { return index_ == 0; }
77
Danil Chapovalov398a7c62017-10-24 17:07:05 +020078 private:
Danil Chapovalov5c3cc412017-12-07 10:15:53 +010079 const rtcp::RtcpPacket::PacketReadyCallback callback_;
Danil Chapovalov398a7c62017-10-24 17:07:05 +020080 const size_t max_packet_size_;
81 size_t index_ = 0;
82 uint8_t buffer_[IP_PACKET_SIZE];
83};
84
Danil Chapovalov398a7c62017-10-24 17:07:05 +020085RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010086 : config_(config), ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020087 RTC_CHECK(config_.Validate());
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010088 if (config_.schedule_periodic_compound_packets)
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010089 SchedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020090}
91
92RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
93
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +010094void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet,
95 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010096 while (!packet.empty()) {
97 rtcp::CommonHeader rtcp_block;
98 if (!rtcp_block.Parse(packet.data(), packet.size()))
99 return;
100
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100101 HandleReceivedPacket(rtcp_block, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100102
103 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
104 packet = packet.subview(rtcp_block.packet_size());
105 }
106}
107
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200108void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100109 SendPeriodicCompoundPacket();
110 ReschedulePeriodicCompoundPackets();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100111}
112
Danil Chapovalovd3282292017-11-13 13:46:02 +0100113void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
114 std::vector<uint32_t> ssrcs) {
115 RTC_DCHECK_GE(bitrate_bps, 0);
116 remb_.emplace();
117 remb_->SetSsrcs(std::move(ssrcs));
118 remb_->SetBitrateBps(bitrate_bps);
119 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
120 // immideately on large bitrate change when there is one RtcpTransceiver per
121 // rtp transport.
122}
123
124void RtcpTransceiverImpl::UnsetRemb() {
125 remb_.reset();
126}
127
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100128void RtcpTransceiverImpl::SendNack(uint32_t ssrc,
129 std::vector<uint16_t> sequence_numbers) {
130 RTC_DCHECK(!sequence_numbers.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100131 rtcp::Nack nack;
132 nack.SetSenderSsrc(config_.feedback_ssrc);
133 nack.SetMediaSsrc(ssrc);
134 nack.SetPacketIds(std::move(sequence_numbers));
135 SendImmediateFeedback(nack);
Danil Chapovalov327c43c2017-11-27 17:23:04 +0100136}
137
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100138void RtcpTransceiverImpl::SendPictureLossIndication(uint32_t ssrc) {
139 rtcp::Pli pli;
140 pli.SetSenderSsrc(config_.feedback_ssrc);
141 pli.SetMediaSsrc(ssrc);
142 SendImmediateFeedback(pli);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100143}
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100144
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100145void RtcpTransceiverImpl::SendFullIntraRequest(
146 rtc::ArrayView<const uint32_t> ssrcs) {
147 RTC_DCHECK(!ssrcs.empty());
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100148 rtcp::Fir fir;
149 fir.SetSenderSsrc(config_.feedback_ssrc);
150 for (uint32_t media_ssrc : ssrcs)
151 fir.AddRequestTo(media_ssrc,
152 remote_senders_[media_ssrc].fir_sequence_number++);
153 SendImmediateFeedback(fir);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100154}
155
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100156void RtcpTransceiverImpl::HandleReceivedPacket(
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100157 const rtcp::CommonHeader& rtcp_packet_header,
158 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100159 switch (rtcp_packet_header.type()) {
Danil Chapovalov319a6752017-11-30 14:56:52 +0100160 case rtcp::SenderReport::kPacketType:
161 HandleSenderReport(rtcp_packet_header, now_us);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100162 break;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100163 case rtcp::ExtendedReports::kPacketType:
164 HandleExtendedReports(rtcp_packet_header, now_us);
165 break;
166 }
167}
168
169void RtcpTransceiverImpl::HandleSenderReport(
170 const rtcp::CommonHeader& rtcp_packet_header,
171 int64_t now_us) {
172 rtcp::SenderReport sender_report;
173 if (!sender_report.Parse(rtcp_packet_header))
174 return;
175 rtc::Optional<SenderReportTimes>& last =
176 remote_senders_[sender_report.sender_ssrc()].last_received_sender_report;
177 last.emplace();
178 last->local_received_time_us = now_us;
179 last->remote_sent_time = sender_report.ntp();
180}
181
182void RtcpTransceiverImpl::HandleExtendedReports(
183 const rtcp::CommonHeader& rtcp_packet_header,
184 int64_t now_us) {
185 rtcp::ExtendedReports extended_reports;
186 if (!extended_reports.Parse(rtcp_packet_header))
187 return;
188 if (extended_reports.dlrr() && config_.non_sender_rtt_measurement &&
189 config_.rtt_observer) {
190 // Delay and last_rr are transferred using 32bit compact ntp resolution.
191 // Convert packet arrival time to same format through 64bit ntp format.
192 uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(now_us));
193 for (const rtcp::ReceiveTimeInfo& rti :
194 extended_reports.dlrr().sub_blocks()) {
195 if (rti.ssrc != config_.feedback_ssrc)
196 continue;
197 uint32_t rtt_ntp =
198 receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
199 int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
200 config_.rtt_observer->OnRttUpdate(rtt_ms);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100201 }
202 }
203}
204
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100205void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
206 if (!config_.schedule_periodic_compound_packets)
207 return;
208 // Stop existent send task.
209 ptr_factory_.InvalidateWeakPtrs();
210 SchedulePeriodicCompoundPackets(config_.report_period_ms);
211}
212
Danil Chapovalovc0fd5f92017-11-16 14:35:32 +0100213void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100214 class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100215 public:
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100216 SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
217 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100218 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
219 bool Run() override {
220 RTC_DCHECK(task_queue_->IsCurrent());
221 if (!ptr_)
222 return true;
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100223 ptr_->SendPeriodicCompoundPacket();
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100224 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
225 ptr_->config_.report_period_ms);
226 return false;
227 }
228
229 private:
230 rtc::TaskQueue* const task_queue_;
231 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
232 };
233
234 RTC_DCHECK(config_.schedule_periodic_compound_packets);
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100235
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100236 auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100237 config_.task_queue, ptr_factory_.GetWeakPtr());
238 if (delay_ms > 0)
239 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
240 else
241 config_.task_queue->PostTask(std::move(task));
242}
243
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100244void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
245 RTC_DCHECK(sender->IsEmpty());
Danil Chapovalovd3282292017-11-13 13:46:02 +0100246 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov319a6752017-11-30 14:56:52 +0100247 int64_t now_us = rtc::TimeMicros();
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100248 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100249 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalov319a6752017-11-30 14:56:52 +0100250 receiver_report.SetReportBlocks(CreateReportBlocks(now_us));
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100251 sender->AppendPacket(receiver_report);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100252
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200253 if (!config_.cname.empty()) {
254 rtcp::Sdes sdes;
255 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
256 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
257 << " to rtcp sdes packet.";
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100258 sender->AppendPacket(sdes);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200259 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100260 if (remb_) {
261 remb_->SetSenderSsrc(sender_ssrc);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100262 sender->AppendPacket(*remb_);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100263 }
Danil Chapovalov319a6752017-11-30 14:56:52 +0100264 // TODO(bugs.webrtc.org/8239): Do not send rrtr if this packet starts with
265 // SenderReport instead of ReceiverReport
266 // when RtcpTransceiver supports rtp senders.
267 if (config_.non_sender_rtt_measurement) {
268 rtcp::ExtendedReports xr;
269
270 rtcp::Rrtr rrtr;
271 rrtr.SetNtp(TimeMicrosToNtp(now_us));
272 xr.SetRrtr(rrtr);
273
274 xr.SetSenderSsrc(sender_ssrc);
275 sender->AppendPacket(xr);
276 }
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100277}
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200278
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100279void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100280 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
281 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
282 };
283 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalova7e418c2017-11-21 11:08:53 +0100284 CreateCompoundPacket(&sender);
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200285 sender.Send();
286}
287
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100288void RtcpTransceiverImpl::SendImmediateFeedback(
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100289 const rtcp::RtcpPacket& rtcp_packet) {
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100290 auto send_packet = [this](rtc::ArrayView<const uint8_t> packet) {
291 config_.outgoing_transport->SendRtcp(packet.data(), packet.size());
292 };
293 PacketSender sender(send_packet, config_.max_packet_size);
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100294 // Compound mode requires every sent rtcp packet to be compound, i.e. start
295 // with a sender or receiver report.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100296 if (config_.rtcp_mode == RtcpMode::kCompound)
297 CreateCompoundPacket(&sender);
298
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100299 sender.AppendPacket(rtcp_packet);
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100300 sender.Send();
301
Danil Chapovalov8d19e032017-11-28 19:53:33 +0100302 // If compound packet was sent, delay (reschedule) the periodic one.
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100303 if (config_.rtcp_mode == RtcpMode::kCompound)
304 ReschedulePeriodicCompoundPackets();
305}
306
Danil Chapovalov319a6752017-11-30 14:56:52 +0100307std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
308 int64_t now_us) {
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100309 if (!config_.receive_statistics)
310 return {};
311 // TODO(danilchap): Support sending more than
312 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
313 std::vector<rtcp::ReportBlock> report_blocks =
314 config_.receive_statistics->RtcpReportBlocks(
315 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
316 for (rtcp::ReportBlock& report_block : report_blocks) {
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100317 auto it = remote_senders_.find(report_block.source_ssrc());
318 if (it == remote_senders_.end() || !it->second.last_received_sender_report)
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100319 continue;
Danil Chapovalov2ddf98d2017-11-22 14:00:41 +0100320 const SenderReportTimes& last_sender_report =
321 *it->second.last_received_sender_report;
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100322 report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time));
323 report_block.SetDelayLastSr(SaturatedUsToCompactNtp(
Danil Chapovalov319a6752017-11-30 14:56:52 +0100324 now_us - last_sender_report.local_received_time_us));
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100325 }
326 return report_blocks;
327}
328
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200329} // namespace webrtc