blob: d6127a959239a034394c013cb437c7bcc5c3e981 [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 Chapovalov398a7c62017-10-24 17:07:05 +020020#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
21#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Danil Chapovalov78161ca2017-10-26 12:09:41 +020022#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010023#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
24#include "modules/rtp_rtcp/source/time_util.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020025#include "rtc_base/checks.h"
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010026#include "rtc_base/ptr_util.h"
27#include "rtc_base/task_queue.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020028
29namespace webrtc {
30namespace {
31
32// Helper to put several RTCP packets into lower layer datagram composing
33// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
34class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
35 public:
36 PacketSender(Transport* transport, size_t max_packet_size)
37 : transport_(transport), max_packet_size_(max_packet_size) {
38 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
39 }
40 ~PacketSender() override {
41 RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet.";
42 }
43
44 // Appends a packet to pending compound packet.
45 // Sends rtcp compound packet if buffer was already full and resets buffer.
46 void AppendPacket(const rtcp::RtcpPacket& packet) {
47 packet.Create(buffer_, &index_, max_packet_size_, this);
48 }
49
50 // Sends pending rtcp compound packet.
51 void Send() {
52 if (index_ > 0) {
53 OnPacketReady(buffer_, index_);
54 index_ = 0;
55 }
56 }
57
58 private:
59 // Implements RtcpPacket::PacketReadyCallback
60 void OnPacketReady(uint8_t* data, size_t length) override {
61 transport_->SendRtcp(data, length);
62 }
63
64 Transport* const transport_;
65 const size_t max_packet_size_;
66 size_t index_ = 0;
67 uint8_t buffer_[IP_PACKET_SIZE];
68};
69
70} // namespace
71
72RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010073 : config_(config), ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020074 RTC_CHECK(config_.Validate());
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010075 if (config_.schedule_periodic_compound_packets)
76 ReschedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020077}
78
79RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
80
Danil Chapovalovd2f37d82017-11-09 15:42:28 +010081void RtcpTransceiverImpl::ReceivePacket(rtc::ArrayView<const uint8_t> packet) {
82 while (!packet.empty()) {
83 rtcp::CommonHeader rtcp_block;
84 if (!rtcp_block.Parse(packet.data(), packet.size()))
85 return;
86
87 HandleReceivedPacket(rtcp_block);
88
89 // TODO(danilchap): Use packet.remove_prefix() when that function exists.
90 packet = packet.subview(rtcp_block.packet_size());
91 }
92}
93
Danil Chapovalov398a7c62017-10-24 17:07:05 +020094void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010095 SendPacket();
96 if (config_.schedule_periodic_compound_packets)
97 ReschedulePeriodicCompoundPackets(config_.report_period_ms);
98}
99
Danil Chapovalovd3282292017-11-13 13:46:02 +0100100void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
101 std::vector<uint32_t> ssrcs) {
102 RTC_DCHECK_GE(bitrate_bps, 0);
103 remb_.emplace();
104 remb_->SetSsrcs(std::move(ssrcs));
105 remb_->SetBitrateBps(bitrate_bps);
106 // TODO(bugs.webrtc.org/8239): Move logic from PacketRouter for sending remb
107 // immideately on large bitrate change when there is one RtcpTransceiver per
108 // rtp transport.
109}
110
111void RtcpTransceiverImpl::UnsetRemb() {
112 remb_.reset();
113}
114
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100115void RtcpTransceiverImpl::HandleReceivedPacket(
116 const rtcp::CommonHeader& rtcp_packet_header) {
117 switch (rtcp_packet_header.type()) {
118 case rtcp::SenderReport::kPacketType: {
119 rtcp::SenderReport sender_report;
120 if (!sender_report.Parse(rtcp_packet_header))
121 return;
122 SenderReportTimes& last =
123 last_received_sender_reports_[sender_report.sender_ssrc()];
124 last.local_received_time_us = rtc::TimeMicros();
125 last.remote_sent_time = sender_report.ntp();
126 break;
127 }
128 }
129}
130
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +0100131void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets(int64_t delay_ms) {
132 class SendPeriodicCompoundPacket : public rtc::QueuedTask {
133 public:
134 SendPeriodicCompoundPacket(rtc::TaskQueue* task_queue,
135 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
136 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
137 bool Run() override {
138 RTC_DCHECK(task_queue_->IsCurrent());
139 if (!ptr_)
140 return true;
141 ptr_->SendPacket();
142 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
143 ptr_->config_.report_period_ms);
144 return false;
145 }
146
147 private:
148 rtc::TaskQueue* const task_queue_;
149 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
150 };
151
152 RTC_DCHECK(config_.schedule_periodic_compound_packets);
153 RTC_DCHECK(config_.task_queue->IsCurrent());
154
155 // Stop existent send task if there is one.
156 ptr_factory_.InvalidateWeakPtrs();
157 auto task = rtc::MakeUnique<SendPeriodicCompoundPacket>(
158 config_.task_queue, ptr_factory_.GetWeakPtr());
159 if (delay_ms > 0)
160 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
161 else
162 config_.task_queue->PostTask(std::move(task));
163}
164
165void RtcpTransceiverImpl::SendPacket() {
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200166 PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
Danil Chapovalovd3282292017-11-13 13:46:02 +0100167 const uint32_t sender_ssrc = config_.feedback_ssrc;
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200168
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100169 rtcp::ReceiverReport receiver_report;
Danil Chapovalovd3282292017-11-13 13:46:02 +0100170 receiver_report.SetSenderSsrc(sender_ssrc);
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100171 receiver_report.SetReportBlocks(CreateReportBlocks());
172 sender.AppendPacket(receiver_report);
173
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200174 if (!config_.cname.empty()) {
175 rtcp::Sdes sdes;
176 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
177 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
178 << " to rtcp sdes packet.";
179 sender.AppendPacket(sdes);
180 }
Danil Chapovalovd3282292017-11-13 13:46:02 +0100181 if (remb_) {
182 remb_->SetSenderSsrc(sender_ssrc);
183 sender.AppendPacket(*remb_);
184 }
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200185
186 sender.Send();
187}
188
Danil Chapovalovd2f37d82017-11-09 15:42:28 +0100189std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks() {
190 if (!config_.receive_statistics)
191 return {};
192 // TODO(danilchap): Support sending more than
193 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
194 std::vector<rtcp::ReportBlock> report_blocks =
195 config_.receive_statistics->RtcpReportBlocks(
196 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
197 for (rtcp::ReportBlock& report_block : report_blocks) {
198 auto it = last_received_sender_reports_.find(report_block.source_ssrc());
199 if (it == last_received_sender_reports_.end())
200 continue;
201 const SenderReportTimes& last_sender_report = it->second;
202 report_block.SetLastSr(CompactNtp(last_sender_report.remote_sent_time));
203 report_block.SetDelayLastSr(SaturatedUsToCompactNtp(
204 rtc::TimeMicros() - last_sender_report.local_received_time_us));
205 }
206 return report_blocks;
207}
208
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200209} // namespace webrtc