Moving src/webrtc into src/.

In order to eliminate the WebRTC Subtree mirror in Chromium, 
WebRTC is moving the content of the src/webrtc directory up
to the src/ directory.

NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
TBR=tommi@webrtc.org

Bug: chromium:611808
Change-Id: Iac59c5b51b950f174119565bac87955a7994bc38
Reviewed-on: https://webrtc-review.googlesource.com/1560
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Henrik Kjellander <kjellander@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19845}
This commit is contained in:
Mirko Bonadei
2017-09-15 06:15:48 +02:00
committed by Commit Bot
parent 6674846b4a
commit bb547203bf
4576 changed files with 1092 additions and 1196 deletions

View File

@ -0,0 +1,163 @@
/*
* 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 "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include <algorithm>
#include <memory>
#include <vector>
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/rate_limiter.h"
#include "webrtc/test/null_transport.h"
namespace webrtc {
void LoopBackTransport::SetSendModule(RtpRtcp* rtp_rtcp_module,
RTPPayloadRegistry* payload_registry,
RtpReceiver* receiver,
ReceiveStatistics* receive_statistics) {
rtp_rtcp_module_ = rtp_rtcp_module;
rtp_payload_registry_ = payload_registry;
rtp_receiver_ = receiver;
receive_statistics_ = receive_statistics;
}
void LoopBackTransport::DropEveryNthPacket(int n) {
packet_loss_ = n;
}
bool LoopBackTransport::SendRtp(const uint8_t* data,
size_t len,
const PacketOptions& options) {
count_++;
if (packet_loss_ > 0) {
if ((count_ % packet_loss_) == 0) {
return true;
}
}
RTPHeader header;
std::unique_ptr<RtpHeaderParser> parser(RtpHeaderParser::Create());
if (!parser->Parse(data, len, &header)) {
return false;
}
PayloadUnion payload_specific;
if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
&payload_specific)) {
return false;
}
const uint8_t* payload = data + header.headerLength;
RTC_CHECK_GE(len, header.headerLength);
const size_t payload_length = len - header.headerLength;
receive_statistics_->IncomingPacket(header, len, false);
return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
payload_specific, true);
}
bool LoopBackTransport::SendRtcp(const uint8_t* data, size_t len) {
rtp_rtcp_module_->IncomingRtcpPacket((const uint8_t*)data, len);
return true;
}
int32_t TestRtpReceiver::OnReceivedPayloadData(
const uint8_t* payload_data,
size_t payload_size,
const webrtc::WebRtcRTPHeader* rtp_header) {
EXPECT_LE(payload_size, sizeof(payload_data_));
memcpy(payload_data_, payload_data, payload_size);
memcpy(&rtp_header_, rtp_header, sizeof(rtp_header_));
payload_size_ = payload_size;
return 0;
}
class RtpRtcpAPITest : public ::testing::Test {
protected:
RtpRtcpAPITest()
: fake_clock_(123456), retransmission_rate_limiter_(&fake_clock_, 1000) {
test_csrcs_.push_back(1234);
test_csrcs_.push_back(2345);
test_ssrc_ = 3456;
test_timestamp_ = 4567;
test_sequence_number_ = 2345;
}
~RtpRtcpAPITest() {}
const uint32_t initial_ssrc = 8888;
void SetUp() override {
RtpRtcp::Configuration configuration;
configuration.audio = true;
configuration.clock = &fake_clock_;
configuration.outgoing_transport = &null_transport_;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
module_.reset(RtpRtcp::CreateRtpRtcp(configuration));
module_->SetSSRC(initial_ssrc);
rtp_payload_registry_.reset(new RTPPayloadRegistry());
}
std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry_;
std::unique_ptr<RtpRtcp> module_;
uint32_t test_ssrc_;
uint32_t test_timestamp_;
uint16_t test_sequence_number_;
std::vector<uint32_t> test_csrcs_;
SimulatedClock fake_clock_;
test::NullTransport null_transport_;
RateLimiter retransmission_rate_limiter_;
};
TEST_F(RtpRtcpAPITest, Basic) {
module_->SetSequenceNumber(test_sequence_number_);
EXPECT_EQ(test_sequence_number_, module_->SequenceNumber());
module_->SetStartTimestamp(test_timestamp_);
EXPECT_EQ(test_timestamp_, module_->StartTimestamp());
EXPECT_FALSE(module_->Sending());
EXPECT_EQ(0, module_->SetSendingStatus(true));
EXPECT_TRUE(module_->Sending());
}
TEST_F(RtpRtcpAPITest, PacketSize) {
module_->SetMaxRtpPacketSize(1234);
EXPECT_EQ(1234u, module_->MaxRtpPacketSize());
}
TEST_F(RtpRtcpAPITest, SSRC) {
module_->SetSSRC(test_ssrc_);
EXPECT_EQ(test_ssrc_, module_->SSRC());
}
TEST_F(RtpRtcpAPITest, RTCP) {
EXPECT_EQ(RtcpMode::kOff, module_->RTCP());
module_->SetRTCPStatus(RtcpMode::kCompound);
EXPECT_EQ(RtcpMode::kCompound, module_->RTCP());
EXPECT_EQ(0, module_->SetCNAME("john.doe@test.test"));
EXPECT_FALSE(module_->TMMBR());
module_->SetTMMBRStatus(true);
EXPECT_TRUE(module_->TMMBR());
module_->SetTMMBRStatus(false);
EXPECT_FALSE(module_->TMMBR());
}
TEST_F(RtpRtcpAPITest, RtxSender) {
module_->SetRtxSendStatus(kRtxRetransmitted);
EXPECT_EQ(kRtxRetransmitted, module_->RtxSendStatus());
module_->SetRtxSendStatus(kRtxOff);
EXPECT_EQ(kRtxOff, module_->RtxSendStatus());
module_->SetRtxSendStatus(kRtxRetransmitted);
EXPECT_EQ(kRtxRetransmitted, module_->RtxSendStatus());
}
} // namespace webrtc

View File

@ -0,0 +1,72 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_
#define WEBRTC_MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_
#include "webrtc/api/call/transport.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
// This class sends all its packet straight to the provided RtpRtcp module.
// with optional packet loss.
class LoopBackTransport : public Transport {
public:
LoopBackTransport()
: count_(0),
packet_loss_(0),
rtp_payload_registry_(NULL),
rtp_receiver_(NULL),
rtp_rtcp_module_(NULL) {}
void SetSendModule(RtpRtcp* rtp_rtcp_module,
RTPPayloadRegistry* payload_registry,
RtpReceiver* receiver,
ReceiveStatistics* receive_statistics);
void DropEveryNthPacket(int n);
bool SendRtp(const uint8_t* data,
size_t len,
const PacketOptions& options) override;
bool SendRtcp(const uint8_t* data, size_t len) override;
private:
int count_;
int packet_loss_;
ReceiveStatistics* receive_statistics_;
RTPPayloadRegistry* rtp_payload_registry_;
RtpReceiver* rtp_receiver_;
RtpRtcp* rtp_rtcp_module_;
};
class TestRtpReceiver : public RtpData {
public:
int32_t OnReceivedPayloadData(
const uint8_t* payload_data,
size_t payload_size,
const webrtc::WebRtcRTPHeader* rtp_header) override;
const uint8_t* payload_data() const { return payload_data_; }
size_t payload_size() const { return payload_size_; }
webrtc::WebRtcRTPHeader rtp_header() const { return rtp_header_; }
private:
uint8_t payload_data_[1500];
size_t payload_size_;
webrtc::WebRtcRTPHeader rtp_header_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_TEST_TESTAPI_TEST_API_H_

View File

@ -0,0 +1,287 @@
/*
* 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 <algorithm>
#include <memory>
#include <vector>
#include "webrtc/common_types.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/rtp_receiver_audio.h"
#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include "webrtc/rtc_base/rate_limiter.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace {
const uint32_t kTestRate = 64000u;
const uint8_t kTestPayload[] = { 't', 'e', 's', 't' };
const uint8_t kPcmuPayloadType = 96;
const uint8_t kDtmfPayloadType = 97;
struct CngCodecSpec {
int payload_type;
int clockrate_hz;
};
const CngCodecSpec kCngCodecs[] = {{13, 8000},
{103, 16000},
{104, 32000},
{105, 48000}};
bool IsComfortNoisePayload(uint8_t payload_type) {
for (const auto& c : kCngCodecs) {
if (c.payload_type == payload_type)
return true;
}
return false;
}
class VerifyingAudioReceiver : public RtpData {
public:
int32_t OnReceivedPayloadData(
const uint8_t* payloadData,
size_t payloadSize,
const webrtc::WebRtcRTPHeader* rtpHeader) override {
const uint8_t payload_type = rtpHeader->header.payloadType;
if (payload_type == kPcmuPayloadType || payload_type == kDtmfPayloadType) {
EXPECT_EQ(sizeof(kTestPayload), payloadSize);
// All our test vectors for PCMU and DTMF are equal to |kTestPayload|.
const size_t min_size = std::min(sizeof(kTestPayload), payloadSize);
EXPECT_EQ(0, memcmp(payloadData, kTestPayload, min_size));
} else if (IsComfortNoisePayload(payload_type)) {
// CNG types should be recognized properly.
EXPECT_EQ(kAudioFrameCN, rtpHeader->frameType);
EXPECT_TRUE(rtpHeader->type.Audio.isCNG);
}
return 0;
}
};
class RTPCallback : public NullRtpFeedback {
public:
int32_t OnInitializeDecoder(int8_t payloadType,
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
int frequency,
size_t channels,
uint32_t rate) override {
EXPECT_EQ(0u, rate) << "The rate should be zero";
return 0;
}
};
} // namespace
class RtpRtcpAudioTest : public ::testing::Test {
protected:
RtpRtcpAudioTest()
: fake_clock(123456), retransmission_rate_limiter_(&fake_clock, 1000) {
test_CSRC[0] = 1234;
test_CSRC[2] = 2345;
test_ssrc = 3456;
test_timestamp = 4567;
test_sequence_number = 2345;
}
~RtpRtcpAudioTest() {}
void SetUp() override {
receive_statistics1_.reset(ReceiveStatistics::Create(&fake_clock));
receive_statistics2_.reset(ReceiveStatistics::Create(&fake_clock));
rtp_payload_registry1_.reset(new RTPPayloadRegistry());
rtp_payload_registry2_.reset(new RTPPayloadRegistry());
RtpRtcp::Configuration configuration;
configuration.audio = true;
configuration.clock = &fake_clock;
configuration.receive_statistics = receive_statistics1_.get();
configuration.outgoing_transport = &transport1;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
module1.reset(RtpRtcp::CreateRtpRtcp(configuration));
rtp_receiver1_.reset(RtpReceiver::CreateAudioReceiver(
&fake_clock, &data_receiver1, &rtp_callback,
rtp_payload_registry1_.get()));
configuration.receive_statistics = receive_statistics2_.get();
configuration.outgoing_transport = &transport2;
module2.reset(RtpRtcp::CreateRtpRtcp(configuration));
rtp_receiver2_.reset(RtpReceiver::CreateAudioReceiver(
&fake_clock, &data_receiver2, &rtp_callback,
rtp_payload_registry2_.get()));
transport1.SetSendModule(module2.get(), rtp_payload_registry2_.get(),
rtp_receiver2_.get(), receive_statistics2_.get());
transport2.SetSendModule(module1.get(), rtp_payload_registry1_.get(),
rtp_receiver1_.get(), receive_statistics1_.get());
}
void RegisterPayload(const CodecInst& codec) {
EXPECT_EQ(0, module1->RegisterSendPayload(codec));
EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload(codec));
EXPECT_EQ(0, module2->RegisterSendPayload(codec));
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(codec));
}
VerifyingAudioReceiver data_receiver1;
VerifyingAudioReceiver data_receiver2;
RTPCallback rtp_callback;
std::unique_ptr<ReceiveStatistics> receive_statistics1_;
std::unique_ptr<ReceiveStatistics> receive_statistics2_;
std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry1_;
std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry2_;
std::unique_ptr<RtpReceiver> rtp_receiver1_;
std::unique_ptr<RtpReceiver> rtp_receiver2_;
std::unique_ptr<RtpRtcp> module1;
std::unique_ptr<RtpRtcp> module2;
LoopBackTransport transport1;
LoopBackTransport transport2;
uint32_t test_ssrc;
uint32_t test_timestamp;
uint16_t test_sequence_number;
uint32_t test_CSRC[webrtc::kRtpCsrcSize];
SimulatedClock fake_clock;
RateLimiter retransmission_rate_limiter_;
};
TEST_F(RtpRtcpAudioTest, Basic) {
module1->SetSSRC(test_ssrc);
module1->SetStartTimestamp(test_timestamp);
// Test detection at the end of a DTMF tone.
// EXPECT_EQ(0, module2->SetTelephoneEventForwardToDecoder(true));
EXPECT_EQ(0, module1->SetSendingStatus(true));
// Start basic RTP test.
// Send an empty RTP packet.
// Should fail since we have not registered the payload type.
EXPECT_FALSE(module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
kPcmuPayloadType, 0, -1, nullptr, 0,
nullptr, nullptr, nullptr));
CodecInst voice_codec = {};
voice_codec.pltype = kPcmuPayloadType;
voice_codec.plfreq = 8000;
voice_codec.rate = kTestRate;
memcpy(voice_codec.plname, "PCMU", 5);
RegisterPayload(voice_codec);
EXPECT_TRUE(module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
kPcmuPayloadType, 0, -1, kTestPayload,
4, nullptr, nullptr, nullptr));
EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC());
uint32_t timestamp;
EXPECT_TRUE(rtp_receiver2_->Timestamp(&timestamp));
EXPECT_EQ(test_timestamp, timestamp);
}
TEST_F(RtpRtcpAudioTest, DTMF) {
CodecInst voice_codec = {};
voice_codec.pltype = kPcmuPayloadType;
voice_codec.plfreq = 8000;
voice_codec.rate = kTestRate;
memcpy(voice_codec.plname, "PCMU", 5);
RegisterPayload(voice_codec);
module1->SetSSRC(test_ssrc);
module1->SetStartTimestamp(test_timestamp);
EXPECT_EQ(0, module1->SetSendingStatus(true));
// Prepare for DTMF.
voice_codec.pltype = kDtmfPayloadType;
voice_codec.plfreq = 8000;
memcpy(voice_codec.plname, "telephone-event", 16);
EXPECT_EQ(0, module1->RegisterSendPayload(voice_codec));
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(voice_codec));
// Start DTMF test.
int timeStamp = 160;
// Send a DTMF tone using RFC 2833 (4733).
for (int i = 0; i < 16; i++) {
EXPECT_EQ(0, module1->SendTelephoneEventOutband(i, timeStamp, 10));
}
timeStamp += 160; // Prepare for next packet.
// Send RTP packets for 16 tones a 160 ms 100ms
// pause between = 2560ms + 1600ms = 4160ms
for (; timeStamp <= 250 * 160; timeStamp += 160) {
EXPECT_TRUE(module1->SendOutgoingData(
webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1,
kTestPayload, 4, nullptr, nullptr, nullptr));
fake_clock.AdvanceTimeMilliseconds(20);
module1->Process();
}
EXPECT_EQ(0, module1->SendTelephoneEventOutband(32, 9000, 10));
for (; timeStamp <= 740 * 160; timeStamp += 160) {
EXPECT_TRUE(module1->SendOutgoingData(
webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1,
kTestPayload, 4, nullptr, nullptr, nullptr));
fake_clock.AdvanceTimeMilliseconds(20);
module1->Process();
}
}
TEST_F(RtpRtcpAudioTest, ComfortNoise) {
module1->SetSSRC(test_ssrc);
module1->SetStartTimestamp(test_timestamp);
EXPECT_EQ(0, module1->SetSendingStatus(true));
// Register PCMU and all four comfort noise codecs
CodecInst voice_codec = {};
voice_codec.pltype = kPcmuPayloadType;
voice_codec.plfreq = 8000;
voice_codec.rate = kTestRate;
memcpy(voice_codec.plname, "PCMU", 5);
RegisterPayload(voice_codec);
for (const auto& c : kCngCodecs) {
CodecInst cng_codec = {};
cng_codec.pltype = c.payload_type;
cng_codec.plfreq = c.clockrate_hz;
memcpy(cng_codec.plname, "CN", 3);
RegisterPayload(cng_codec);
}
// Transmit comfort noise packets interleaved by PCMU packets.
uint32_t in_timestamp = 0;
for (const auto& c : kCngCodecs) {
uint32_t timestamp;
EXPECT_TRUE(module1->SendOutgoingData(
webrtc::kAudioFrameSpeech, kPcmuPayloadType, in_timestamp, -1,
kTestPayload, 4, nullptr, nullptr, nullptr));
EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC());
EXPECT_TRUE(rtp_receiver2_->Timestamp(&timestamp));
EXPECT_EQ(test_timestamp + in_timestamp, timestamp);
in_timestamp += 10;
EXPECT_TRUE(module1->SendOutgoingData(webrtc::kAudioFrameCN, c.payload_type,
in_timestamp, -1, kTestPayload, 1,
nullptr, nullptr, nullptr));
EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC());
EXPECT_TRUE(rtp_receiver2_->Timestamp(&timestamp));
EXPECT_EQ(test_timestamp + in_timestamp, timestamp);
in_timestamp += 10;
}
}
} // namespace webrtc

View File

@ -0,0 +1,249 @@
/*
* 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 <algorithm>
#include <memory>
#include <vector>
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/include/receive_statistics.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/rtp_receiver_audio.h"
#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
#include "webrtc/rtc_base/rate_limiter.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace {
class RtcpCallback : public RtcpIntraFrameObserver {
public:
void SetModule(RtpRtcp* module) {
_rtpRtcpModule = module;
}
virtual void OnRTCPPacketTimeout(const int32_t id) {
}
virtual void OnLipSyncUpdate(const int32_t id,
const int32_t audioVideoOffset) {}
virtual void OnReceivedIntraFrameRequest(uint32_t ssrc) {}
private:
RtpRtcp* _rtpRtcpModule;
};
class TestRtpFeedback : public NullRtpFeedback {
public:
explicit TestRtpFeedback(RtpRtcp* rtp_rtcp) : rtp_rtcp_(rtp_rtcp) {}
virtual ~TestRtpFeedback() {}
void OnIncomingSSRCChanged(uint32_t ssrc) override {
rtp_rtcp_->SetRemoteSSRC(ssrc);
}
private:
RtpRtcp* rtp_rtcp_;
};
class RtpRtcpRtcpTest : public ::testing::Test {
protected:
RtpRtcpRtcpTest()
: fake_clock(123456), retransmission_rate_limiter_(&fake_clock, 1000) {
test_csrcs.push_back(1234);
test_csrcs.push_back(2345);
test_ssrc = 3456;
test_timestamp = 4567;
test_sequence_number = 2345;
}
~RtpRtcpRtcpTest() {}
virtual void SetUp() {
receiver = new TestRtpReceiver();
transport1 = new LoopBackTransport();
transport2 = new LoopBackTransport();
myRTCPFeedback1 = new RtcpCallback();
myRTCPFeedback2 = new RtcpCallback();
receive_statistics1_.reset(ReceiveStatistics::Create(&fake_clock));
receive_statistics2_.reset(ReceiveStatistics::Create(&fake_clock));
RtpRtcp::Configuration configuration;
configuration.audio = true;
configuration.clock = &fake_clock;
configuration.receive_statistics = receive_statistics1_.get();
configuration.outgoing_transport = transport1;
configuration.intra_frame_callback = myRTCPFeedback1;
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
rtp_payload_registry1_.reset(new RTPPayloadRegistry());
rtp_payload_registry2_.reset(new RTPPayloadRegistry());
module1 = RtpRtcp::CreateRtpRtcp(configuration);
rtp_feedback1_.reset(new TestRtpFeedback(module1));
rtp_receiver1_.reset(RtpReceiver::CreateAudioReceiver(
&fake_clock, receiver, rtp_feedback1_.get(),
rtp_payload_registry1_.get()));
configuration.receive_statistics = receive_statistics2_.get();
configuration.outgoing_transport = transport2;
configuration.intra_frame_callback = myRTCPFeedback2;
module2 = RtpRtcp::CreateRtpRtcp(configuration);
rtp_feedback2_.reset(new TestRtpFeedback(module2));
rtp_receiver2_.reset(RtpReceiver::CreateAudioReceiver(
&fake_clock, receiver, rtp_feedback2_.get(),
rtp_payload_registry2_.get()));
transport1->SetSendModule(module2, rtp_payload_registry2_.get(),
rtp_receiver2_.get(), receive_statistics2_.get());
transport2->SetSendModule(module1, rtp_payload_registry1_.get(),
rtp_receiver1_.get(), receive_statistics1_.get());
myRTCPFeedback1->SetModule(module1);
myRTCPFeedback2->SetModule(module2);
module1->SetRTCPStatus(RtcpMode::kCompound);
module2->SetRTCPStatus(RtcpMode::kCompound);
module2->SetSSRC(test_ssrc + 1);
module1->SetSSRC(test_ssrc);
module1->SetSequenceNumber(test_sequence_number);
module1->SetStartTimestamp(test_timestamp);
module1->SetCsrcs(test_csrcs);
EXPECT_EQ(0, module1->SetCNAME("john.doe@test.test"));
EXPECT_EQ(0, module1->SetSendingStatus(true));
CodecInst voice_codec;
voice_codec.pltype = 96;
voice_codec.plfreq = 8000;
voice_codec.rate = 64000;
memcpy(voice_codec.plname, "PCMU", 5);
EXPECT_EQ(0, module1->RegisterSendPayload(voice_codec));
EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload(voice_codec));
EXPECT_EQ(0, module2->RegisterSendPayload(voice_codec));
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(voice_codec));
// We need to send one RTP packet to get the RTCP packet to be accepted by
// the receiving module.
// send RTP packet with the data "testtest"
const uint8_t test[9] = "testtest";
EXPECT_EQ(true,
module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96, 0, -1,
test, 8, nullptr, nullptr, nullptr));
}
virtual void TearDown() {
delete module1;
delete module2;
delete myRTCPFeedback1;
delete myRTCPFeedback2;
delete transport1;
delete transport2;
delete receiver;
}
std::unique_ptr<TestRtpFeedback> rtp_feedback1_;
std::unique_ptr<TestRtpFeedback> rtp_feedback2_;
std::unique_ptr<ReceiveStatistics> receive_statistics1_;
std::unique_ptr<ReceiveStatistics> receive_statistics2_;
std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry1_;
std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry2_;
std::unique_ptr<RtpReceiver> rtp_receiver1_;
std::unique_ptr<RtpReceiver> rtp_receiver2_;
RtpRtcp* module1;
RtpRtcp* module2;
TestRtpReceiver* receiver;
LoopBackTransport* transport1;
LoopBackTransport* transport2;
RtcpCallback* myRTCPFeedback1;
RtcpCallback* myRTCPFeedback2;
uint32_t test_ssrc;
uint32_t test_timestamp;
uint16_t test_sequence_number;
std::vector<uint32_t> test_csrcs;
SimulatedClock fake_clock;
RateLimiter retransmission_rate_limiter_;
};
TEST_F(RtpRtcpRtcpTest, RTCP_CNAME) {
uint32_t testOfCSRC[webrtc::kRtpCsrcSize];
EXPECT_EQ(2, rtp_receiver2_->CSRCs(testOfCSRC));
EXPECT_EQ(test_csrcs[0], testOfCSRC[0]);
EXPECT_EQ(test_csrcs[1], testOfCSRC[1]);
// Set cname of mixed.
EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[0], "john@192.168.0.1"));
EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[1], "jane@192.168.0.2"));
EXPECT_EQ(-1, module1->RemoveMixedCNAME(test_csrcs[0] + 1));
EXPECT_EQ(0, module1->RemoveMixedCNAME(test_csrcs[1]));
EXPECT_EQ(0, module1->AddMixedCNAME(test_csrcs[1], "jane@192.168.0.2"));
// send RTCP packet, triggered by timer
fake_clock.AdvanceTimeMilliseconds(7500);
module1->Process();
fake_clock.AdvanceTimeMilliseconds(100);
module2->Process();
char cName[RTCP_CNAME_SIZE];
EXPECT_EQ(-1, module2->RemoteCNAME(rtp_receiver2_->SSRC() + 1, cName));
// Check multiple CNAME.
EXPECT_EQ(0, module2->RemoteCNAME(rtp_receiver2_->SSRC(), cName));
EXPECT_EQ(0, strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module2->RemoteCNAME(test_csrcs[0], cName));
EXPECT_EQ(0, strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module2->RemoteCNAME(test_csrcs[1], cName));
EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE));
EXPECT_EQ(0, module1->SetSendingStatus(false));
// Test that BYE clears the CNAME
EXPECT_EQ(-1, module2->RemoteCNAME(rtp_receiver2_->SSRC(), cName));
}
TEST_F(RtpRtcpRtcpTest, RemoteRTCPStatRemote) {
std::vector<RTCPReportBlock> report_blocks;
EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks));
EXPECT_EQ(0u, report_blocks.size());
// send RTCP packet, triggered by timer
fake_clock.AdvanceTimeMilliseconds(7500);
module1->Process();
fake_clock.AdvanceTimeMilliseconds(100);
module2->Process();
EXPECT_EQ(0, module1->RemoteRTCPStat(&report_blocks));
ASSERT_EQ(1u, report_blocks.size());
// |test_ssrc+1| is the SSRC of module2 that send the report.
EXPECT_EQ(test_ssrc + 1, report_blocks[0].sender_ssrc);
EXPECT_EQ(test_ssrc, report_blocks[0].source_ssrc);
EXPECT_EQ(0u, report_blocks[0].packets_lost);
EXPECT_LT(0u, report_blocks[0].delay_since_last_sender_report);
EXPECT_EQ(test_sequence_number,
report_blocks[0].extended_highest_sequence_number);
EXPECT_EQ(0u, report_blocks[0].fraction_lost);
}
} // namespace
} // namespace webrtc

View File

@ -0,0 +1,184 @@
/*
* 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

View File

@ -0,0 +1,191 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_RTP_RTCP_TEST_TESTFEC_AVERAGE_RESIDUAL_LOSS_XOR_CODES_H_
#define WEBRTC_MODULES_RTP_RTCP_TEST_TESTFEC_AVERAGE_RESIDUAL_LOSS_XOR_CODES_H_
namespace webrtc {
// Maximum number of media packets allowed in this test. The burst mask types
// are currently defined up to (kMaxMediaPacketsTest, kMaxMediaPacketsTest).
const int kMaxMediaPacketsTest = 12;
// Maximum number of FEC codes considered in this test.
const int kNumberCodes = kMaxMediaPacketsTest * (kMaxMediaPacketsTest + 1) / 2;
// For the random mask type: reference level for the maximum average residual
// loss expected for each code size up to:
// (kMaxMediaPacketsTest, kMaxMediaPacketsTest).
const float kMaxResidualLossRandomMask[kNumberCodes] = {
0.009463f,
0.022436f,
0.007376f,
0.033895f,
0.012423f,
0.004644f,
0.043438f,
0.019937f,
0.008820f,
0.003438f,
0.051282f,
0.025795f,
0.012872f,
0.006458f,
0.003195f,
0.057728f,
0.032146f,
0.016708f,
0.009242f,
0.005054f,
0.003078f,
0.063050f,
0.037261f,
0.021767f,
0.012447f,
0.007099f,
0.003826f,
0.002504f,
0.067476f,
0.042348f,
0.026169f,
0.015695f,
0.009478f,
0.005887f,
0.003568f,
0.001689f,
0.071187f,
0.046575f,
0.031697f,
0.019797f,
0.012433f,
0.007027f,
0.004845f,
0.002777f,
0.001753f,
0.074326f,
0.050628f,
0.034978f,
0.021955f,
0.014821f,
0.009462f,
0.006393f,
0.004181f,
0.003105f,
0.001231f,
0.077008f,
0.054226f,
0.038407f,
0.026251f,
0.018634f,
0.011568f,
0.008130f,
0.004957f,
0.003334f,
0.002069f,
0.001304f,
0.079318f,
0.057180f,
0.041268f,
0.028842f,
0.020033f,
0.014061f,
0.009636f,
0.006411f,
0.004583f,
0.002817f,
0.001770f,
0.001258f
};
// For the bursty mask type: reference level for the maximum average residual
// loss expected for each code size up to:
// (kMaxMediaPacketsTestf, kMaxMediaPacketsTest).
const float kMaxResidualLossBurstyMask[kNumberCodes] = {
0.033236f,
0.053344f,
0.026616f,
0.064129f,
0.036589f,
0.021892f,
0.071055f,
0.043890f,
0.028009f,
0.018524f,
0.075968f,
0.049828f,
0.033288f,
0.022791f,
0.016088f,
0.079672f,
0.054586f,
0.037872f,
0.026679f,
0.019326f,
0.014293f,
0.082582f,
0.058719f,
0.042045f,
0.030504f,
0.022391f,
0.016894f,
0.012946f,
0.084935f,
0.062169f,
0.045620f,
0.033713f,
0.025570f,
0.019439f,
0.015121f,
0.011920f,
0.086881f,
0.065267f,
0.048721f,
0.037613f,
0.028278f,
0.022152f,
0.017314f,
0.013791f,
0.011130f,
0.088516f,
0.067911f,
0.051709f,
0.040819f,
0.030777f,
0.024547f,
0.019689f,
0.015877f,
0.012773f,
0.010516f,
0.089909f,
0.070332f,
0.054402f,
0.043210f,
0.034096f,
0.026625f,
0.021823f,
0.017648f,
0.014649f,
0.011982f,
0.010035f,
0.091109f,
0.072428f,
0.056775f,
0.045418f,
0.036679f,
0.028599f,
0.023693f,
0.019966f,
0.016603f,
0.013690f,
0.011359f,
0.009657f
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_TEST_TESTFEC_AVERAGE_RESIDUAL_LOSS_XOR_CODES_H_

View File

@ -0,0 +1,475 @@
/*
* 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.
*/
/*
* Test application for core FEC algorithm. Calls encoding and decoding
* functions in ForwardErrorCorrection directly.
*/
#include <string.h>
#include <time.h>
#include <list>
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h"
#include "webrtc/rtc_base/random.h"
#include "webrtc/test/gtest.h"
#include "webrtc/test/testsupport/fileutils.h"
// #define VERBOSE_OUTPUT
namespace webrtc {
namespace fec_private_tables {
extern const uint8_t** kPacketMaskBurstyTbl[12];
}
namespace test {
using fec_private_tables::kPacketMaskBurstyTbl;
void ReceivePackets(
ForwardErrorCorrection::ReceivedPacketList* to_decode_list,
ForwardErrorCorrection::ReceivedPacketList* received_packet_list,
size_t num_packets_to_decode,
float reorder_rate,
float duplicate_rate,
Random* random) {
RTC_DCHECK(to_decode_list->empty());
RTC_DCHECK_LE(num_packets_to_decode, received_packet_list->size());
for (size_t i = 0; i < num_packets_to_decode; i++) {
auto it = received_packet_list->begin();
// Reorder packets.
float random_variable = random->Rand<float>();
while (random_variable < reorder_rate) {
++it;
if (it == received_packet_list->end()) {
--it;
break;
}
random_variable = random->Rand<float>();
}
to_decode_list->push_back(std::move(*it));
received_packet_list->erase(it);
// Duplicate packets.
ForwardErrorCorrection::ReceivedPacket* received_packet =
to_decode_list->back().get();
random_variable = random->Rand<float>();
while (random_variable < duplicate_rate) {
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> duplicate_packet(
new ForwardErrorCorrection::ReceivedPacket());
*duplicate_packet = *received_packet;
duplicate_packet->pkt = new ForwardErrorCorrection::Packet();
memcpy(duplicate_packet->pkt->data, received_packet->pkt->data,
received_packet->pkt->length);
duplicate_packet->pkt->length = received_packet->pkt->length;
to_decode_list->push_back(std::move(duplicate_packet));
random_variable = random->Rand<float>();
}
}
}
void RunTest(bool use_flexfec) {
// TODO(marpan): Split this function into subroutines/helper functions.
enum { kMaxNumberMediaPackets = 48 };
enum { kMaxNumberFecPackets = 48 };
const uint32_t kNumMaskBytesL0 = 2;
const uint32_t kNumMaskBytesL1 = 6;
// FOR UEP
const bool kUseUnequalProtection = true;
// FEC mask types.
const FecMaskType kMaskTypes[] = {kFecMaskRandom, kFecMaskBursty};
const int kNumFecMaskTypes = sizeof(kMaskTypes) / sizeof(*kMaskTypes);
// Maximum number of media packets allowed for the mask type.
const uint16_t kMaxMediaPackets[] = {
kMaxNumberMediaPackets,
sizeof(kPacketMaskBurstyTbl) / sizeof(*kPacketMaskBurstyTbl)};
ASSERT_EQ(12, kMaxMediaPackets[1]) << "Max media packets for bursty mode not "
<< "equal to 12.";
ForwardErrorCorrection::PacketList media_packet_list;
std::list<ForwardErrorCorrection::Packet*> fec_packet_list;
ForwardErrorCorrection::ReceivedPacketList to_decode_list;
ForwardErrorCorrection::ReceivedPacketList received_packet_list;
ForwardErrorCorrection::RecoveredPacketList recovered_packet_list;
std::list<uint8_t*> fec_mask_list;
// Running over only two loss rates to limit execution time.
const float loss_rate[] = {0.05f, 0.01f};
const uint32_t loss_rate_size = sizeof(loss_rate) / sizeof(*loss_rate);
const float reorder_rate = 0.1f;
const float duplicate_rate = 0.1f;
uint8_t media_loss_mask[kMaxNumberMediaPackets];
uint8_t fec_loss_mask[kMaxNumberFecPackets];
uint8_t fec_packet_masks[kMaxNumberFecPackets][kMaxNumberMediaPackets];
// Seed the random number generator, storing the seed to file in order to
// reproduce past results.
const unsigned int random_seed = static_cast<unsigned int>(time(nullptr));
Random random(random_seed);
std::string filename = webrtc::test::OutputPath() + "randomSeedLog.txt";
FILE* random_seed_file = fopen(filename.c_str(), "a");
fprintf(random_seed_file, "%u\n", random_seed);
fclose(random_seed_file);
random_seed_file = nullptr;
uint16_t seq_num = 0;
uint32_t timestamp = random.Rand<uint32_t>();
const uint32_t media_ssrc = random.Rand(1u, 0xfffffffe);
uint32_t fec_ssrc;
uint16_t fec_seq_num_offset;
if (use_flexfec) {
fec_ssrc = random.Rand(1u, 0xfffffffe);
fec_seq_num_offset = random.Rand(0, 1 << 15);
} else {
fec_ssrc = media_ssrc;
fec_seq_num_offset = 0;
}
std::unique_ptr<ForwardErrorCorrection> fec;
if (use_flexfec) {
fec = ForwardErrorCorrection::CreateFlexfec(fec_ssrc, media_ssrc);
} else {
RTC_DCHECK_EQ(media_ssrc, fec_ssrc);
fec = ForwardErrorCorrection::CreateUlpfec(fec_ssrc);
}
// Loop over the mask types: random and bursty.
for (int mask_type_idx = 0; mask_type_idx < kNumFecMaskTypes;
++mask_type_idx) {
for (uint32_t loss_rate_idx = 0; loss_rate_idx < loss_rate_size;
++loss_rate_idx) {
printf("Loss rate: %.2f, Mask type %d \n", loss_rate[loss_rate_idx],
mask_type_idx);
const uint32_t packet_mask_max = kMaxMediaPackets[mask_type_idx];
std::unique_ptr<uint8_t[]> packet_mask(
new uint8_t[packet_mask_max * kNumMaskBytesL1]);
FecMaskType fec_mask_type = kMaskTypes[mask_type_idx];
for (uint32_t num_media_packets = 1; num_media_packets <= packet_mask_max;
num_media_packets++) {
internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets);
for (uint32_t num_fec_packets = 1;
num_fec_packets <= num_media_packets &&
num_fec_packets <= packet_mask_max;
num_fec_packets++) {
// Loop over num_imp_packets: usually <= (0.3*num_media_packets).
// For this test we check up to ~ (num_media_packets / 4).
uint32_t max_num_imp_packets = num_media_packets / 4 + 1;
for (uint32_t num_imp_packets = 0;
num_imp_packets <= max_num_imp_packets &&
num_imp_packets <= packet_mask_max;
num_imp_packets++) {
uint8_t protection_factor =
static_cast<uint8_t>(num_fec_packets * 255 / num_media_packets);
const uint32_t mask_bytes_per_fec_packet =
(num_media_packets > 16) ? kNumMaskBytesL1 : kNumMaskBytesL0;
memset(packet_mask.get(), 0,
num_media_packets * mask_bytes_per_fec_packet);
// Transfer packet masks from bit-mask to byte-mask.
internal::GeneratePacketMasks(num_media_packets, num_fec_packets,
num_imp_packets,
kUseUnequalProtection,
mask_table, packet_mask.get());
#ifdef VERBOSE_OUTPUT
printf(
"%u media packets, %u FEC packets, %u num_imp_packets, "
"loss rate = %.2f \n",
num_media_packets, num_fec_packets, num_imp_packets,
loss_rate[loss_rate_idx]);
printf("Packet mask matrix \n");
#endif
for (uint32_t i = 0; i < num_fec_packets; i++) {
for (uint32_t j = 0; j < num_media_packets; j++) {
const uint8_t byte_mask =
packet_mask[i * mask_bytes_per_fec_packet + j / 8];
const uint32_t bit_position = (7 - j % 8);
fec_packet_masks[i][j] =
(byte_mask & (1 << bit_position)) >> bit_position;
#ifdef VERBOSE_OUTPUT
printf("%u ", fec_packet_masks[i][j]);
#endif
}
#ifdef VERBOSE_OUTPUT
printf("\n");
#endif
}
#ifdef VERBOSE_OUTPUT
printf("\n");
#endif
// Check for all zero rows or columns: indicates incorrect mask.
uint32_t row_limit = num_media_packets;
for (uint32_t i = 0; i < num_fec_packets; ++i) {
uint32_t row_sum = 0;
for (uint32_t j = 0; j < row_limit; ++j) {
row_sum += fec_packet_masks[i][j];
}
ASSERT_NE(0u, row_sum) << "Row is all zero " << i;
}
for (uint32_t j = 0; j < row_limit; ++j) {
uint32_t column_sum = 0;
for (uint32_t i = 0; i < num_fec_packets; ++i) {
column_sum += fec_packet_masks[i][j];
}
ASSERT_NE(0u, column_sum) << "Column is all zero " << j;
}
// Construct media packets.
// Reset the sequence number here for each FEC code/mask tested
// below, to avoid sequence number wrap-around. In actual decoding,
// old FEC packets in list are dropped if sequence number wrap
// around is detected. This case is currently not handled below.
seq_num = 0;
for (uint32_t i = 0; i < num_media_packets; ++i) {
std::unique_ptr<ForwardErrorCorrection::Packet> media_packet(
new ForwardErrorCorrection::Packet());
const uint32_t kMinPacketSize = 12;
const uint32_t kMaxPacketSize = static_cast<uint32_t>(
IP_PACKET_SIZE - 12 - 28 - fec->MaxPacketOverhead());
media_packet->length = random.Rand(kMinPacketSize,
kMaxPacketSize);
// Generate random values for the first 2 bytes.
media_packet->data[0] = random.Rand<uint8_t>();
media_packet->data[1] = random.Rand<uint8_t>();
// The first two bits are assumed to be 10 by the
// FEC encoder. In fact the FEC decoder will set the
// two first bits to 10 regardless of what they
// actually were. Set the first two bits to 10
// so that a memcmp can be performed for the
// whole restored packet.
media_packet->data[0] |= 0x80;
media_packet->data[0] &= 0xbf;
// FEC is applied to a whole frame.
// A frame is signaled by multiple packets without
// the marker bit set followed by the last packet of
// the frame for which the marker bit is set.
// Only push one (fake) frame to the FEC.
media_packet->data[1] &= 0x7f;
ByteWriter<uint16_t>::WriteBigEndian(&media_packet->data[2],
seq_num);
ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[4],
timestamp);
ByteWriter<uint32_t>::WriteBigEndian(&media_packet->data[8],
media_ssrc);
// Generate random values for payload
for (size_t j = 12; j < media_packet->length; ++j) {
media_packet->data[j] = random.Rand<uint8_t>();
}
media_packet_list.push_back(std::move(media_packet));
seq_num++;
}
media_packet_list.back()->data[1] |= 0x80;
ASSERT_EQ(0, fec->EncodeFec(media_packet_list, protection_factor,
num_imp_packets, kUseUnequalProtection,
fec_mask_type, &fec_packet_list))
<< "EncodeFec() failed";
ASSERT_EQ(num_fec_packets, fec_packet_list.size())
<< "We requested " << num_fec_packets << " FEC packets, but "
<< "EncodeFec() produced " << fec_packet_list.size();
memset(media_loss_mask, 0, sizeof(media_loss_mask));
uint32_t media_packet_idx = 0;
for (const auto& media_packet : media_packet_list) {
// We want a value between 0 and 1.
const float loss_random_variable = random.Rand<float>();
if (loss_random_variable >= loss_rate[loss_rate_idx]) {
media_loss_mask[media_packet_idx] = 1;
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
received_packet(
new ForwardErrorCorrection::ReceivedPacket());
received_packet->pkt = new ForwardErrorCorrection::Packet();
received_packet->pkt->length = media_packet->length;
memcpy(received_packet->pkt->data, media_packet->data,
media_packet->length);
received_packet->ssrc = media_ssrc;
received_packet->seq_num =
ByteReader<uint16_t>::ReadBigEndian(&media_packet->data[2]);
received_packet->is_fec = false;
received_packet_list.push_back(std::move(received_packet));
}
media_packet_idx++;
}
memset(fec_loss_mask, 0, sizeof(fec_loss_mask));
uint32_t fec_packet_idx = 0;
for (auto* fec_packet : fec_packet_list) {
const float loss_random_variable = random.Rand<float>();
if (loss_random_variable >= loss_rate[loss_rate_idx]) {
fec_loss_mask[fec_packet_idx] = 1;
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
received_packet(
new ForwardErrorCorrection::ReceivedPacket());
received_packet->pkt = new ForwardErrorCorrection::Packet();
received_packet->pkt->length = fec_packet->length;
memcpy(received_packet->pkt->data, fec_packet->data,
fec_packet->length);
received_packet->seq_num = fec_seq_num_offset + seq_num;
received_packet->is_fec = true;
received_packet->ssrc = fec_ssrc;
received_packet_list.push_back(std::move(received_packet));
fec_mask_list.push_back(fec_packet_masks[fec_packet_idx]);
}
++fec_packet_idx;
++seq_num;
}
#ifdef VERBOSE_OUTPUT
printf("Media loss mask:\n");
for (uint32_t i = 0; i < num_media_packets; i++) {
printf("%u ", media_loss_mask[i]);
}
printf("\n\n");
printf("FEC loss mask:\n");
for (uint32_t i = 0; i < num_fec_packets; i++) {
printf("%u ", fec_loss_mask[i]);
}
printf("\n\n");
#endif
auto fec_mask_it = fec_mask_list.begin();
while (fec_mask_it != fec_mask_list.end()) {
uint32_t hamming_dist = 0;
uint32_t recovery_position = 0;
for (uint32_t i = 0; i < num_media_packets; i++) {
if (media_loss_mask[i] == 0 && (*fec_mask_it)[i] == 1) {
recovery_position = i;
++hamming_dist;
}
}
auto item_to_delete = fec_mask_it;
++fec_mask_it;
if (hamming_dist == 1) {
// Recovery possible. Restart search.
media_loss_mask[recovery_position] = 1;
fec_mask_it = fec_mask_list.begin();
} else if (hamming_dist == 0) {
// FEC packet cannot provide further recovery.
fec_mask_list.erase(item_to_delete);
}
}
#ifdef VERBOSE_OUTPUT
printf("Recovery mask:\n");
for (uint32_t i = 0; i < num_media_packets; ++i) {
printf("%u ", media_loss_mask[i]);
}
printf("\n\n");
#endif
// For error-checking frame completion.
bool fec_packet_received = false;
while (!received_packet_list.empty()) {
size_t num_packets_to_decode = random.Rand(
1u, static_cast<uint32_t>(received_packet_list.size()));
ReceivePackets(&to_decode_list, &received_packet_list,
num_packets_to_decode, reorder_rate,
duplicate_rate, &random);
if (fec_packet_received == false) {
for (const auto& received_packet : to_decode_list) {
if (received_packet->is_fec) {
fec_packet_received = true;
}
}
}
ASSERT_EQ(0,
fec->DecodeFec(&to_decode_list, &recovered_packet_list))
<< "DecodeFec() failed";
ASSERT_TRUE(to_decode_list.empty())
<< "Received packet list is not empty.";
}
media_packet_idx = 0;
for (const auto& media_packet : media_packet_list) {
if (media_loss_mask[media_packet_idx] == 1) {
// Should have recovered this packet.
auto recovered_packet_list_it = recovered_packet_list.cbegin();
ASSERT_FALSE(recovered_packet_list_it ==
recovered_packet_list.end())
<< "Insufficient number of recovered packets.";
ForwardErrorCorrection::RecoveredPacket* recovered_packet =
recovered_packet_list_it->get();
ASSERT_EQ(recovered_packet->pkt->length, media_packet->length)
<< "Recovered packet length not identical to original "
<< "media packet";
ASSERT_EQ(0, memcmp(recovered_packet->pkt->data,
media_packet->data, media_packet->length))
<< "Recovered packet payload not identical to original "
<< "media packet";
recovered_packet_list.pop_front();
}
++media_packet_idx;
}
fec->ResetState(&recovered_packet_list);
ASSERT_TRUE(recovered_packet_list.empty())
<< "Excessive number of recovered packets.\t size is: "
<< recovered_packet_list.size();
// -- Teardown --
media_packet_list.clear();
// Clear FEC packet list, so we don't pass in a non-empty
// list in the next call to DecodeFec().
fec_packet_list.clear();
// Delete received packets we didn't pass to DecodeFec(), due to
// early frame completion.
received_packet_list.clear();
while (!fec_mask_list.empty()) {
fec_mask_list.pop_front();
}
timestamp += 90000 / 30;
} // loop over num_imp_packets
} // loop over FecPackets
} // loop over num_media_packets
} // loop over loss rates
} // loop over mask types
// Have DecodeFec clear the recovered packet list.
fec->ResetState(&recovered_packet_list);
ASSERT_TRUE(recovered_packet_list.empty())
<< "Recovered packet list is not empty";
}
TEST(FecTest, UlpfecTest) {
RunTest(false);
}
TEST(FecTest, FlexfecTest) {
RunTest(true);
}
} // namespace test
} // namespace webrtc

File diff suppressed because it is too large Load Diff