Create skeleton of the rtcp transceiver.

RtcpTransceiver name reserved for thread-safe version that planned to
be wrapper of the RtcpTransceiverImpl

BUG=webrtc:8239

Change-Id: If8a3092eb1b8e4175e3efd23b52e1043cdabf19f
Reviewed-on: https://webrtc-review.googlesource.com/7920
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20414}
This commit is contained in:
Danil Chapovalov
2017-10-24 17:07:05 +02:00
committed by Commit Bot
parent d5585ca956
commit 398a7c67b1
6 changed files with 357 additions and 0 deletions

View File

@ -218,6 +218,23 @@ rtc_static_library("rtp_rtcp") {
} }
} }
rtc_source_set("rtcp_transceiver") {
public = [
"source/rtcp_transceiver_config.h",
"source/rtcp_transceiver_impl.h",
]
sources = [
"source/rtcp_transceiver_config.cc",
"source/rtcp_transceiver_impl.cc",
]
deps = [
":rtp_rtcp",
"../../api:array_view",
"../../api:transport_api",
"../../rtc_base:rtc_base_approved",
]
}
rtc_source_set("fec_test_helper") { rtc_source_set("fec_test_helper") {
testonly = true testonly = true
sources = [ sources = [
@ -338,6 +355,7 @@ if (rtc_include_tests) {
"source/rtcp_packet_unittest.cc", "source/rtcp_packet_unittest.cc",
"source/rtcp_receiver_unittest.cc", "source/rtcp_receiver_unittest.cc",
"source/rtcp_sender_unittest.cc", "source/rtcp_sender_unittest.cc",
"source/rtcp_transceiver_impl_unittest.cc",
"source/rtp_fec_unittest.cc", "source/rtp_fec_unittest.cc",
"source/rtp_format_h264_unittest.cc", "source/rtp_format_h264_unittest.cc",
"source/rtp_format_video_generic_unittest.cc", "source/rtp_format_video_generic_unittest.cc",
@ -366,6 +384,7 @@ if (rtc_include_tests) {
deps = [ deps = [
":fec_test_helper", ":fec_test_helper",
":mock_rtp_rtcp", ":mock_rtp_rtcp",
":rtcp_transceiver",
":rtp_rtcp", ":rtp_rtcp",
"..:module_api", "..:module_api",
"../..:webrtc_common", "../..:webrtc_common",

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/logging.h"
namespace webrtc {
RtcpTransceiverConfig::RtcpTransceiverConfig() = default;
RtcpTransceiverConfig::RtcpTransceiverConfig(const RtcpTransceiverConfig&) =
default;
RtcpTransceiverConfig& RtcpTransceiverConfig::operator=(
const RtcpTransceiverConfig&) = default;
RtcpTransceiverConfig::~RtcpTransceiverConfig() = default;
bool RtcpTransceiverConfig::Validate() const {
if (feedback_ssrc == 0)
LOG(LS_WARNING)
<< debug_id
<< "Ssrc 0 may be treated by some implementation as invalid.";
if (cname.size() > 255) {
LOG(LS_ERROR) << debug_id << "cname can be maximum 255 characters.";
return false;
}
if (max_packet_size < 100) {
LOG(LS_ERROR) << debug_id << "max packet size " << max_packet_size
<< " is too small.";
return false;
}
if (max_packet_size > IP_PACKET_SIZE) {
LOG(LS_ERROR) << debug_id << "max packet size " << max_packet_size
<< " more than " << IP_PACKET_SIZE << " is unsupported.";
return false;
}
if (outgoing_transport == nullptr) {
LOG(LS_ERROR) << debug_id << "outgoing transport must be set";
return false;
}
if (min_periodic_report_ms <= 0) {
LOG(LS_ERROR) << debug_id << "period " << min_periodic_report_ms
<< "ms between reports should be positive.";
return false;
}
// TODO(danilchap): Remove or update the warning when RtcpTransceiver supports
// send-only sessions.
if (receive_statistics == nullptr)
LOG(LS_WARNING)
<< debug_id
<< "receive statistic should be set to generate rtcp report blocks.";
return true;
}
} // namespace webrtc

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_
#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_
#include <string>
namespace webrtc {
class ReceiveStatisticsProvider;
class Transport;
struct RtcpTransceiverConfig {
RtcpTransceiverConfig();
RtcpTransceiverConfig(const RtcpTransceiverConfig&);
RtcpTransceiverConfig& operator=(const RtcpTransceiverConfig&);
~RtcpTransceiverConfig();
// Logs the error and returns false if configuration miss key objects or
// is inconsistant. May log warnings.
bool Validate() const;
// Used to prepend all log messages. Can be empty.
std::string debug_id;
// Ssrc to use as default sender ssrc, e.g. for transport-wide feedbacks.
uint32_t feedback_ssrc = 1;
// Cname of the local particiapnt.
std::string cname;
// Maximum packet size outgoing transport accepts.
size_t max_packet_size = 1200;
// Transport to send rtcp packets to. Should be set.
Transport* outgoing_transport = nullptr;
// Minimum period to send receiver reports and attached messages.
int min_periodic_report_ms = 1000;
// Rtcp report block generator for outgoing receiver reports.
ReceiveStatisticsProvider* receive_statistics = nullptr;
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_CONFIG_H_

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
#include <utility>
#include <vector>
#include "api/call/transport.h"
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
// Helper to put several RTCP packets into lower layer datagram composing
// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
public:
PacketSender(Transport* transport, size_t max_packet_size)
: transport_(transport), max_packet_size_(max_packet_size) {
RTC_CHECK_LE(max_packet_size, IP_PACKET_SIZE);
}
~PacketSender() override {
RTC_DCHECK_EQ(index_, 0) << "Unsent rtcp packet.";
}
// Appends a packet to pending compound packet.
// Sends rtcp compound packet if buffer was already full and resets buffer.
void AppendPacket(const rtcp::RtcpPacket& packet) {
packet.Create(buffer_, &index_, max_packet_size_, this);
}
// Sends pending rtcp compound packet.
void Send() {
if (index_ > 0) {
OnPacketReady(buffer_, index_);
index_ = 0;
}
}
private:
// Implements RtcpPacket::PacketReadyCallback
void OnPacketReady(uint8_t* data, size_t length) override {
transport_->SendRtcp(data, length);
}
Transport* const transport_;
const size_t max_packet_size_;
size_t index_ = 0;
uint8_t buffer_[IP_PACKET_SIZE];
};
} // namespace
RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
: config_(config) {
RTC_CHECK(config_.Validate());
}
RtcpTransceiverImpl::~RtcpTransceiverImpl() = default;
void RtcpTransceiverImpl::SendCompoundPacket() {
PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
rtcp::ReceiverReport rr;
rr.SetSenderSsrc(config_.feedback_ssrc);
if (config_.receive_statistics) {
// TODO(danilchap): Support sending more than
// |ReceiverReport::kMaxNumberOfReportBlocks| per compound rtcp packet.
std::vector<rtcp::ReportBlock> report_blocks =
config_.receive_statistics->RtcpReportBlocks(
rtcp::ReceiverReport::kMaxNumberOfReportBlocks);
// TODO(danilchap): Fill in LastSr/DelayLastSr fields of report blocks
// when RtcpTransceiver handles incoming sender reports.
rr.SetReportBlocks(std::move(report_blocks));
}
sender.AppendPacket(rr);
// TODO(danilchap): Append SDES to conform to the requirements on minimal
// compound RTCP packet.
sender.Send();
}
} // namespace webrtc

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_
#define MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_
#include <memory>
#include <string>
#include "api/array_view.h"
#include "modules/rtp_rtcp/source/rtcp_transceiver_config.h"
#include "rtc_base/constructormagic.h"
namespace webrtc {
//
// Manage incoming and outgoing rtcp messages for multiple BUNDLED streams.
//
// This class is not thread-safe.
class RtcpTransceiverImpl {
public:
explicit RtcpTransceiverImpl(const RtcpTransceiverConfig& config);
~RtcpTransceiverImpl();
// Sends RTCP packets starting with a sender or receiver report.
void SendCompoundPacket();
private:
const RtcpTransceiverConfig config_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtcpTransceiverImpl);
};
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_RTCP_TRANSCEIVER_IMPL_H_

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/rtcp_transceiver_impl.h"
#include <vector>
#include "modules/rtp_rtcp/include/receive_statistics.h"
#include "rtc_base/ptr_util.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_transport.h"
#include "test/rtcp_packet_parser.h"
namespace {
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SizeIs;
using ::webrtc::MockTransport;
using ::webrtc::RtcpTransceiverConfig;
using ::webrtc::RtcpTransceiverImpl;
using ::webrtc::rtcp::ReportBlock;
using ::webrtc::test::RtcpPacketParser;
class MockReceiveStatisticsProvider : public webrtc::ReceiveStatisticsProvider {
public:
MOCK_METHOD1(RtcpReportBlocks, std::vector<ReportBlock>(size_t));
};
TEST(RtcpTransceiverImplTest, ForceSendReportEmitsRtcpPacket) {
MockTransport outgoing_transport;
RtcpPacketParser rtcp_parser;
EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
.WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
RtcpTransceiverConfig config;
config.outgoing_transport = &outgoing_transport;
RtcpTransceiverImpl rtcp_transceiver(config);
ASSERT_EQ(rtcp_parser.receiver_report()->num_packets(), 0);
rtcp_transceiver.SendCompoundPacket();
EXPECT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
}
TEST(RtcpTransceiverImplTest, ReceiverReportUsesReceiveStatistics) {
const uint32_t kSenderSsrc = 12345;
const uint32_t kMediaSsrc = 54321;
MockTransport outgoing_transport;
RtcpPacketParser rtcp_parser;
EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
.WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
MockReceiveStatisticsProvider receive_statistics;
std::vector<ReportBlock> report_blocks(1);
report_blocks[0].SetMediaSsrc(kMediaSsrc);
EXPECT_CALL(receive_statistics, RtcpReportBlocks(_))
.WillRepeatedly(Return(report_blocks));
RtcpTransceiverConfig config;
config.feedback_ssrc = kSenderSsrc;
config.outgoing_transport = &outgoing_transport;
config.receive_statistics = &receive_statistics;
RtcpTransceiverImpl rtcp_transceiver(config);
rtcp_transceiver.SendCompoundPacket();
ASSERT_GT(rtcp_parser.receiver_report()->num_packets(), 0);
EXPECT_EQ(rtcp_parser.receiver_report()->sender_ssrc(), kSenderSsrc);
ASSERT_THAT(rtcp_parser.receiver_report()->report_blocks(),
SizeIs(report_blocks.size()));
EXPECT_EQ(rtcp_parser.receiver_report()->report_blocks()[0].source_ssrc(),
kMediaSsrc);
}
} // namespace