blob: e6b075f0f7d2bd2fe13325be06e2697fd33648dc [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 <vector>
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include "webrtc/rtc_base/rate_limiter.h"
#include "webrtc/test/gtest.h"
namespace {
const unsigned char kPayloadType = 100;
};
namespace webrtc {
class RtpRtcpVideoTest : public ::testing::Test {
protected:
RtpRtcpVideoTest()
: test_ssrc_(3456),
test_timestamp_(4567),
test_sequence_number_(2345),
fake_clock(123456),
retransmission_rate_limiter_(&fake_clock, 1000) {}
~RtpRtcpVideoTest() {}
virtual void SetUp() {
transport_ = new LoopBackTransport();
receiver_ = new TestRtpReceiver();
receive_statistics_.reset(ReceiveStatistics::Create(&fake_clock));
RtpRtcp::Configuration configuration;
configuration.audio = false;
configuration.clock = &fake_clock;
configuration.outgoing_transport = transport_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
video_module_ = RtpRtcp::CreateRtpRtcp(configuration);
rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver(
&fake_clock, receiver_, NULL, &rtp_payload_registry_));
video_module_->SetRTCPStatus(RtcpMode::kCompound);
video_module_->SetSSRC(test_ssrc_);
video_module_->SetStorePacketsStatus(true, 600);
EXPECT_EQ(0, video_module_->SetSendingStatus(true));
transport_->SetSendModule(video_module_, &rtp_payload_registry_,
rtp_receiver_.get(), receive_statistics_.get());
VideoCodec video_codec;
memset(&video_codec, 0, sizeof(video_codec));
video_codec.plType = 123;
memcpy(video_codec.plName, "I420", 5);
EXPECT_EQ(0, video_module_->RegisterSendPayload(video_codec));
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* dataBuffer,
uint32_t timestamp,
uint32_t sequence_number) {
dataBuffer[0] = static_cast<uint8_t>(0x80); // version 2
dataBuffer[1] = static_cast<uint8_t>(kPayloadType);
ByteWriter<uint16_t>::WriteBigEndian(dataBuffer + 2, sequence_number);
ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + 4, timestamp);
ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + 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;
}
virtual void TearDown() {
delete video_module_;
delete transport_;
delete receiver_;
}
int test_id_;
std::unique_ptr<ReceiveStatistics> receive_statistics_;
RTPPayloadRegistry rtp_payload_registry_;
std::unique_ptr<RtpReceiver> rtp_receiver_;
RtpRtcp* video_module_;
LoopBackTransport* transport_;
TestRtpReceiver* receiver_;
uint32_t test_ssrc_;
uint32_t test_timestamp_;
uint16_t test_sequence_number_;
uint8_t video_frame_[65000];
size_t payload_data_length_;
SimulatedClock fake_clock;
RateLimiter retransmission_rate_limiter_;
};
TEST_F(RtpRtcpVideoTest, BasicVideo) {
uint32_t timestamp = 3000;
EXPECT_TRUE(video_module_->SendOutgoingData(
kVideoFrameDelta, 123, timestamp, timestamp / 90, video_frame_,
payload_data_length_, nullptr, nullptr, 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;
strncpy(codec.plName, "VP8", 4);
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));
PayloadUnion payload_specific;
EXPECT_TRUE(rtp_payload_registry_.GetPayloadSpecifics(header.payloadType,
&payload_specific));
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,
payload_specific, true));
EXPECT_EQ(0u, receiver_->payload_size());
EXPECT_EQ(payload_length, receiver_->rtp_header().header.paddingLength);
}
timestamp += 3000;
fake_clock.AdvanceTimeMilliseconds(33);
}
}
} // namespace webrtc