|  | /* | 
|  | *  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 "testing/gtest/include/gtest/gtest.h" | 
|  | #include "webrtc/base/rate_limiter.h" | 
|  | #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" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const unsigned char kPayloadType = 100; | 
|  |  | 
|  | }; | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | class RtpRtcpVideoTest : public ::testing::Test { | 
|  | protected: | 
|  | RtpRtcpVideoTest() | 
|  | : rtp_payload_registry_(RTPPayloadStrategy::CreateStrategy(false)), | 
|  | 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_receiver_->RegisterReceivePayload(video_codec.plName, | 
|  | video_codec.plType, | 
|  | 90000, | 
|  | 0, | 
|  | video_codec.maxBitrate)); | 
|  |  | 
|  | 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_receiver_->RegisterReceivePayload(codec.plName, | 
|  | codec.plType, | 
|  | 90000, | 
|  | 0, | 
|  | codec.maxBitrate)); | 
|  | 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 |