blob: aa524bdb08e01bb454e7cf2167c021ff7bef0992 [file] [log] [blame]
/*
* Copyright (c) 2012 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 <stdlib.h>
#include <algorithm>
#include <memory>
#include "api/video_codecs/video_codec.h"
#include "modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/byte_io.h"
#include "modules/rtp_rtcp/source/rtp_receiver_video.h"
#include "modules/rtp_rtcp/test/testAPI/test_api.h"
#include "rtc_base/rate_limiter.h"
#include "test/gtest.h"
namespace {
const uint32_t kSsrc = 3456;
const unsigned char kPayloadType = 100;
};
namespace webrtc {
class RtpRtcpVideoTest : public ::testing::Test {
protected:
RtpRtcpVideoTest()
: fake_clock_(123456),
retransmission_rate_limiter_(&fake_clock_, 1000),
receive_statistics_(ReceiveStatistics::Create(&fake_clock_)),
rtp_receiver_(
RtpReceiver::CreateVideoReceiver(&fake_clock_,
&receiver_,
&rtp_payload_registry_)) {}
~RtpRtcpVideoTest() override = default;
void SetUp() override {
RtpRtcp::Configuration configuration;
configuration.audio = false;
configuration.clock = &fake_clock_;
configuration.outgoing_transport = &transport_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
video_module_.reset(RtpRtcp::CreateRtpRtcp(configuration));
video_module_->SetRTCPStatus(RtcpMode::kCompound);
video_module_->SetSSRC(kSsrc);
video_module_->SetStorePacketsStatus(true, 600);
EXPECT_EQ(0, video_module_->SetSendingStatus(true));
transport_.SetSendModule(video_module_.get(), &rtp_payload_registry_,
rtp_receiver_.get(), receive_statistics_.get());
VideoCodec video_codec;
memset(&video_codec, 0, sizeof(video_codec));
video_codec.plType = 123;
video_codec.codecType = kVideoCodecI420;
video_module_->RegisterVideoSendPayload(123, "I420");
EXPECT_EQ(0, rtp_payload_registry_.RegisterReceivePayload(video_codec));
payload_data_length_ = sizeof(video_frame_);
for (size_t n = 0; n < payload_data_length_; n++) {
video_frame_[n] = n % 10;
}
}
size_t BuildRTPheader(uint8_t* buffer,
uint32_t timestamp,
uint32_t sequence_number) {
buffer[0] = static_cast<uint8_t>(0x80); // version 2
buffer[1] = static_cast<uint8_t>(kPayloadType);
ByteWriter<uint16_t>::WriteBigEndian(buffer + 2, sequence_number);
ByteWriter<uint32_t>::WriteBigEndian(buffer + 4, timestamp);
ByteWriter<uint32_t>::WriteBigEndian(buffer + 8, 0x1234); // SSRC.
size_t rtpHeaderLength = 12;
return rtpHeaderLength;
}
size_t PaddingPacket(uint8_t* buffer,
uint32_t timestamp,
uint32_t sequence_number,
size_t bytes) {
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
size_t max_length = 224;
size_t padding_bytes_in_packet = max_length;
if (bytes < max_length) {
padding_bytes_in_packet = (bytes + 16) & 0xffe0; // Keep our modulus 32.
}
// Correct seq num, timestamp and payload type.
size_t header_length = BuildRTPheader(buffer, timestamp, sequence_number);
buffer[0] |= 0x20; // Set padding bit.
int32_t* data = reinterpret_cast<int32_t*>(&(buffer[header_length]));
// Fill data buffer with random data.
for (size_t j = 0; j < (padding_bytes_in_packet >> 2); j++) {
data[j] = rand(); // NOLINT
}
// Set number of padding bytes in the last byte of the packet.
buffer[header_length + padding_bytes_in_packet - 1] =
padding_bytes_in_packet;
return padding_bytes_in_packet + header_length;
}
uint8_t video_frame_[65000];
size_t payload_data_length_;
SimulatedClock fake_clock_;
RateLimiter retransmission_rate_limiter_;
std::unique_ptr<ReceiveStatistics> receive_statistics_;
RTPPayloadRegistry rtp_payload_registry_;
TestRtpReceiver receiver_;
std::unique_ptr<RtpReceiver> rtp_receiver_;
std::unique_ptr<RtpRtcp> video_module_;
LoopBackTransport transport_;
};
TEST_F(RtpRtcpVideoTest, BasicVideo) {
uint32_t timestamp = 3000;
RTPVideoHeader video_header;
EXPECT_TRUE(video_module_->SendOutgoingData(
kVideoFrameDelta, 123, timestamp, timestamp / 90, video_frame_,
payload_data_length_, nullptr, &video_header, nullptr));
}
TEST_F(RtpRtcpVideoTest, PaddingOnlyFrames) {
const size_t kPadSize = 255;
uint8_t padding_packet[kPadSize];
uint32_t seq_num = 0;
uint32_t timestamp = 3000;
VideoCodec codec;
codec.codecType = kVideoCodecVP8;
codec.plType = kPayloadType;
EXPECT_EQ(0, rtp_payload_registry_.RegisterReceivePayload(codec));
for (int frame_idx = 0; frame_idx < 10; ++frame_idx) {
for (int packet_idx = 0; packet_idx < 5; ++packet_idx) {
size_t packet_size =
PaddingPacket(padding_packet, timestamp, seq_num, kPadSize);
++seq_num;
RTPHeader header;
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
EXPECT_TRUE(parser->Parse(padding_packet, packet_size, &header));
const auto pl =
rtp_payload_registry_.PayloadTypeToPayload(header.payloadType);
EXPECT_TRUE(pl);
const uint8_t* payload = padding_packet + header.headerLength;
const size_t payload_length = packet_size - header.headerLength;
EXPECT_TRUE(rtp_receiver_->IncomingRtpPacket(
header, payload, payload_length, pl->typeSpecific));
EXPECT_EQ(0u, receiver_.payload_size());
EXPECT_EQ(payload_length, receiver_.rtp_header().header.paddingLength);
}
timestamp += 3000;
fake_clock_.AdvanceTimeMilliseconds(33);
}
}
} // namespace webrtc