| /* | |
| * 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 "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 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() override = default; | |
| void SetUp() override { | |
| 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_, &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; | |
| 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* 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; | |
| } | |
| void TearDown() override { | |
| 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; | |
| 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 |