blob: 4c4ae9567cddae68d1b0c248983a51ba559c1373 [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>
14#include <vector>
15
16#include "api/call/transport.h"
17#include "modules/rtp_rtcp/include/receive_statistics.h"
18#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
19#include "modules/rtp_rtcp/source/rtcp_packet.h"
20#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 Chapovalov398a7c62017-10-24 17:07:05 +020023#include "rtc_base/checks.h"
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010024#include "rtc_base/ptr_util.h"
25#include "rtc_base/task_queue.h"
Danil Chapovalov398a7c62017-10-24 17:07:05 +020026
27namespace webrtc {
28namespace {
29
30// Helper to put several RTCP packets into lower layer datagram composing
31// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
32class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
33 public:
34 PacketSender(Transport* transport, size_t max_packet_size)
35 : transport_(transport), max_packet_size_(max_packet_size) {
36 RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
37 }
38 ~PacketSender() override {
39 RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet.";
40 }
41
42 // Appends a packet to pending compound packet.
43 // Sends rtcp compound packet if buffer was already full and resets buffer.
44 void AppendPacket(const rtcp::RtcpPacket& packet) {
45 packet.Create(buffer_, &index_, max_packet_size_, this);
46 }
47
48 // Sends pending rtcp compound packet.
49 void Send() {
50 if (index_ > 0) {
51 OnPacketReady(buffer_, index_);
52 index_ = 0;
53 }
54 }
55
56 private:
57 // Implements RtcpPacket::PacketReadyCallback
58 void OnPacketReady(uint8_t* data, size_t length) override {
59 transport_->SendRtcp(data, length);
60 }
61
62 Transport* const transport_;
63 const size_t max_packet_size_;
64 size_t index_ = 0;
65 uint8_t buffer_[IP_PACKET_SIZE];
66};
67
68} // namespace
69
70RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010071 : config_(config), ptr_factory_(this) {
Danil Chapovalov398a7c62017-10-24 17:07:05 +020072 RTC_CHECK(config_.Validate());
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010073 if (config_.schedule_periodic_compound_packets)
74 ReschedulePeriodicCompoundPackets(config_.initial_report_delay_ms);
Danil Chapovalov398a7c62017-10-24 17:07:05 +020075}
76
77RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
78
79void RtcpTransceiverImpl::SendCompoundPacket() {
Danil Chapovalov8c8d49e2017-10-30 15:21:41 +010080 SendPacket();
81 if (config_.schedule_periodic_compound_packets)
82 ReschedulePeriodicCompoundPackets(config_.report_period_ms);
83}
84
85void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets(int64_t delay_ms) {
86 class SendPeriodicCompoundPacket : public rtc::QueuedTask {
87 public:
88 SendPeriodicCompoundPacket(rtc::TaskQueue* task_queue,
89 rtc::WeakPtr<RtcpTransceiverImpl> ptr)
90 : task_queue_(task_queue), ptr_(std::move(ptr)) {}
91 bool Run() override {
92 RTC_DCHECK(task_queue_->IsCurrent());
93 if (!ptr_)
94 return true;
95 ptr_->SendPacket();
96 task_queue_->PostDelayedTask(rtc::WrapUnique(this),
97 ptr_->config_.report_period_ms);
98 return false;
99 }
100
101 private:
102 rtc::TaskQueue* const task_queue_;
103 const rtc::WeakPtr<RtcpTransceiverImpl> ptr_;
104 };
105
106 RTC_DCHECK(config_.schedule_periodic_compound_packets);
107 RTC_DCHECK(config_.task_queue->IsCurrent());
108
109 // Stop existent send task if there is one.
110 ptr_factory_.InvalidateWeakPtrs();
111 auto task = rtc::MakeUnique<SendPeriodicCompoundPacket>(
112 config_.task_queue, ptr_factory_.GetWeakPtr());
113 if (delay_ms > 0)
114 config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
115 else
116 config_.task_queue->PostTask(std::move(task));
117}
118
119void RtcpTransceiverImpl::SendPacket() {
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200120 PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
121
122 rtcp::ReceiverReport rr;
123 rr.SetSenderSsrc(config_.feedback_ssrc);
124 if (config_.receive_statistics) {
125 // TODO(danilchap): Support sending more than
126 // |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
127 std::vector<rtcp::ReportBlock> report_blocks =
128 config_.receive_statistics->RtcpReportBlocks(
129 rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
130 // TODO(danilchap): Fill in LastSr/DelayLastSr fields of report blocks
131 // when RtcpTransceiver handles incoming sender reports.
132 rr.SetReportBlocks(std::move(report_blocks));
133 }
134 sender.AppendPacket(rr);
Danil Chapovalov78161ca2017-10-26 12:09:41 +0200135 if (!config_.cname.empty()) {
136 rtcp::Sdes sdes;
137 bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
138 RTC_DCHECK(added) << "Failed to add cname " << config_.cname
139 << " to rtcp sdes packet.";
140 sender.AppendPacket(sdes);
141 }
Danil Chapovalov398a7c62017-10-24 17:07:05 +0200142
143 sender.Send();
144}
145
146} // namespace webrtc