2012-01-10 14:09:18 +00:00
|
|
|
/*
|
2012-02-29 16:09:51 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2012-01-10 14:09:18 +00:00
|
|
|
*
|
|
|
|
|
* 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>
|
2016-04-27 01:19:58 -07:00
|
|
|
#include <memory>
|
2012-01-10 14:09:18 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
2013-05-29 14:27:38 +00:00
|
|
|
#include "webrtc/common_types.h"
|
2015-11-04 08:31:52 +01:00
|
|
|
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
|
|
|
|
|
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
2013-08-15 23:38:54 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h"
|
2016-09-30 22:29:43 -07:00
|
|
|
#include "webrtc/modules/rtp_rtcp/test/testAPI/test_api.h"
|
2017-07-06 19:44:34 +02:00
|
|
|
#include "webrtc/rtc_base/rate_limiter.h"
|
2016-09-30 22:29:43 -07:00
|
|
|
#include "webrtc/test/gtest.h"
|
2012-01-10 14:09:18 +00:00
|
|
|
|
2015-12-10 12:39:08 -08:00
|
|
|
namespace webrtc {
|
|
|
|
|
namespace {
|
2016-10-05 07:51:44 -07:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2012-01-10 14:09:18 +00:00
|
|
|
|
2017-06-01 00:30:55 -07:00
|
|
|
class VerifyingAudioReceiver : public RtpData {
|
2012-01-10 14:09:18 +00:00
|
|
|
public:
|
2015-03-04 12:58:35 +00:00
|
|
|
int32_t OnReceivedPayloadData(
|
2013-04-08 11:08:41 +00:00
|
|
|
const uint8_t* payloadData,
|
2016-06-14 12:52:54 +02:00
|
|
|
size_t payloadSize,
|
2015-03-04 12:58:35 +00:00
|
|
|
const webrtc::WebRtcRTPHeader* rtpHeader) override {
|
2016-10-05 07:51:44 -07:00
|
|
|
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);
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2013-08-15 23:38:54 +00:00
|
|
|
class RTPCallback : public NullRtpFeedback {
|
2012-01-10 14:09:18 +00:00
|
|
|
public:
|
2017-02-28 14:41:05 -08:00
|
|
|
int32_t OnInitializeDecoder(int8_t payloadType,
|
2015-03-04 12:58:35 +00:00
|
|
|
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
|
2017-02-28 14:41:05 -08:00
|
|
|
int frequency,
|
|
|
|
|
size_t channels,
|
|
|
|
|
uint32_t rate) override {
|
2016-12-06 03:52:18 -08:00
|
|
|
EXPECT_EQ(0u, rate) << "The rate should be zero";
|
2012-01-10 14:09:18 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
} // namespace
|
|
|
|
|
|
2012-01-10 14:09:18 +00:00
|
|
|
class RtpRtcpAudioTest : public ::testing::Test {
|
|
|
|
|
protected:
|
2016-07-29 12:59:36 +02:00
|
|
|
RtpRtcpAudioTest()
|
|
|
|
|
: fake_clock(123456), retransmission_rate_limiter_(&fake_clock, 1000) {
|
2012-01-10 14:09:18 +00:00
|
|
|
test_CSRC[0] = 1234;
|
|
|
|
|
test_CSRC[2] = 2345;
|
|
|
|
|
test_ssrc = 3456;
|
|
|
|
|
test_timestamp = 4567;
|
|
|
|
|
test_sequence_number = 2345;
|
|
|
|
|
}
|
|
|
|
|
~RtpRtcpAudioTest() {}
|
|
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
void SetUp() override {
|
2013-08-15 23:38:54 +00:00
|
|
|
receive_statistics1_.reset(ReceiveStatistics::Create(&fake_clock));
|
|
|
|
|
receive_statistics2_.reset(ReceiveStatistics::Create(&fake_clock));
|
|
|
|
|
|
2016-11-25 06:40:25 -08:00
|
|
|
rtp_payload_registry1_.reset(new RTPPayloadRegistry());
|
|
|
|
|
rtp_payload_registry2_.reset(new RTPPayloadRegistry());
|
2013-08-15 23:38:54 +00:00
|
|
|
|
2012-05-11 11:08:54 +00:00
|
|
|
RtpRtcp::Configuration configuration;
|
|
|
|
|
configuration.audio = true;
|
|
|
|
|
configuration.clock = &fake_clock;
|
2013-08-15 23:38:54 +00:00
|
|
|
configuration.receive_statistics = receive_statistics1_.get();
|
2016-10-05 07:51:44 -07:00
|
|
|
configuration.outgoing_transport = &transport1;
|
2016-07-29 12:59:36 +02:00
|
|
|
configuration.retransmission_rate_limiter = &retransmission_rate_limiter_;
|
2012-05-11 11:08:54 +00:00
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
module1.reset(RtpRtcp::CreateRtpRtcp(configuration));
|
2013-08-15 23:38:54 +00:00
|
|
|
rtp_receiver1_.reset(RtpReceiver::CreateAudioReceiver(
|
2016-10-05 07:51:44 -07:00
|
|
|
&fake_clock, &data_receiver1, &rtp_callback,
|
|
|
|
|
rtp_payload_registry1_.get()));
|
2012-05-11 11:08:54 +00:00
|
|
|
|
2013-08-15 23:38:54 +00:00
|
|
|
configuration.receive_statistics = receive_statistics2_.get();
|
2016-10-05 07:51:44 -07:00
|
|
|
configuration.outgoing_transport = &transport2;
|
2012-05-11 11:08:54 +00:00
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
module2.reset(RtpRtcp::CreateRtpRtcp(configuration));
|
2013-08-15 23:38:54 +00:00
|
|
|
rtp_receiver2_.reset(RtpReceiver::CreateAudioReceiver(
|
2016-10-05 07:51:44 -07:00
|
|
|
&fake_clock, &data_receiver2, &rtp_callback,
|
|
|
|
|
rtp_payload_registry2_.get()));
|
2013-08-15 23:38:54 +00:00
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
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());
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
void RegisterPayload(const CodecInst& codec) {
|
|
|
|
|
EXPECT_EQ(0, module1->RegisterSendPayload(codec));
|
2016-11-24 09:34:46 -08:00
|
|
|
EXPECT_EQ(0, rtp_receiver1_->RegisterReceivePayload(codec));
|
2016-10-05 07:51:44 -07:00
|
|
|
EXPECT_EQ(0, module2->RegisterSendPayload(codec));
|
2016-11-24 09:34:46 -08:00
|
|
|
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(codec));
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
VerifyingAudioReceiver data_receiver1;
|
|
|
|
|
VerifyingAudioReceiver data_receiver2;
|
|
|
|
|
RTPCallback rtp_callback;
|
2016-04-27 01:19:58 -07:00
|
|
|
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_;
|
2016-10-05 07:51:44 -07:00
|
|
|
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;
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t test_ssrc;
|
|
|
|
|
uint32_t test_timestamp;
|
|
|
|
|
uint16_t test_sequence_number;
|
|
|
|
|
uint32_t test_CSRC[webrtc::kRtpCsrcSize];
|
2013-01-21 07:42:11 +00:00
|
|
|
SimulatedClock fake_clock;
|
2016-07-29 12:59:36 +02:00
|
|
|
RateLimiter retransmission_rate_limiter_;
|
2012-01-10 14:09:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST_F(RtpRtcpAudioTest, Basic) {
|
2014-06-05 08:25:29 +00:00
|
|
|
module1->SetSSRC(test_ssrc);
|
2014-12-19 13:49:55 +00:00
|
|
|
module1->SetStartTimestamp(test_timestamp);
|
2012-01-10 14:09:18 +00:00
|
|
|
|
2016-09-22 03:36:27 -07:00
|
|
|
// Test detection at the end of a DTMF tone.
|
|
|
|
|
// EXPECT_EQ(0, module2->SetTelephoneEventForwardToDecoder(true));
|
|
|
|
|
|
2012-01-10 14:09:18 +00:00
|
|
|
EXPECT_EQ(0, module1->SetSendingStatus(true));
|
|
|
|
|
|
|
|
|
|
// Start basic RTP test.
|
|
|
|
|
|
|
|
|
|
// Send an empty RTP packet.
|
2013-08-15 23:38:54 +00:00
|
|
|
// Should fail since we have not registered the payload type.
|
2016-10-05 07:51:44 -07:00
|
|
|
EXPECT_FALSE(module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
|
|
|
|
|
kPcmuPayloadType, 0, -1, nullptr, 0,
|
|
|
|
|
nullptr, nullptr, nullptr));
|
2012-01-10 14:09:18 +00:00
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
CodecInst voice_codec = {};
|
|
|
|
|
voice_codec.pltype = kPcmuPayloadType;
|
2013-08-15 23:38:54 +00:00
|
|
|
voice_codec.plfreq = 8000;
|
2016-10-05 07:51:44 -07:00
|
|
|
voice_codec.rate = kTestRate;
|
2013-08-15 23:38:54 +00:00
|
|
|
memcpy(voice_codec.plname, "PCMU", 5);
|
2016-10-05 07:51:44 -07:00
|
|
|
RegisterPayload(voice_codec);
|
2013-08-15 23:38:54 +00:00
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
EXPECT_TRUE(module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
|
|
|
|
|
kPcmuPayloadType, 0, -1, kTestPayload,
|
|
|
|
|
4, nullptr, nullptr, nullptr));
|
2012-01-10 14:09:18 +00:00
|
|
|
|
2013-08-15 23:38:54 +00:00
|
|
|
EXPECT_EQ(test_ssrc, rtp_receiver2_->SSRC());
|
2013-11-08 15:18:52 +00:00
|
|
|
uint32_t timestamp;
|
|
|
|
|
EXPECT_TRUE(rtp_receiver2_->Timestamp(×tamp));
|
|
|
|
|
EXPECT_EQ(test_timestamp, timestamp);
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(RtpRtcpAudioTest, DTMF) {
|
2016-10-05 07:51:44 -07:00
|
|
|
CodecInst voice_codec = {};
|
|
|
|
|
voice_codec.pltype = kPcmuPayloadType;
|
2013-08-15 23:38:54 +00:00
|
|
|
voice_codec.plfreq = 8000;
|
2016-10-05 07:51:44 -07:00
|
|
|
voice_codec.rate = kTestRate;
|
2013-08-15 23:38:54 +00:00
|
|
|
memcpy(voice_codec.plname, "PCMU", 5);
|
2016-10-05 07:51:44 -07:00
|
|
|
RegisterPayload(voice_codec);
|
2012-01-10 14:09:18 +00:00
|
|
|
|
2014-06-05 08:25:29 +00:00
|
|
|
module1->SetSSRC(test_ssrc);
|
2014-12-19 13:49:55 +00:00
|
|
|
module1->SetStartTimestamp(test_timestamp);
|
2012-01-10 14:09:18 +00:00
|
|
|
EXPECT_EQ(0, module1->SetSendingStatus(true));
|
|
|
|
|
|
|
|
|
|
// Prepare for DTMF.
|
2016-10-05 07:51:44 -07:00
|
|
|
voice_codec.pltype = kDtmfPayloadType;
|
2013-08-15 23:38:54 +00:00
|
|
|
voice_codec.plfreq = 8000;
|
|
|
|
|
memcpy(voice_codec.plname, "telephone-event", 16);
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(0, module1->RegisterSendPayload(voice_codec));
|
2016-11-24 09:34:46 -08:00
|
|
|
EXPECT_EQ(0, rtp_receiver2_->RegisterReceivePayload(voice_codec));
|
2012-01-10 14:09:18 +00:00
|
|
|
|
|
|
|
|
// Start DTMF test.
|
2016-03-11 03:06:41 -08:00
|
|
|
int timeStamp = 160;
|
2012-01-10 14:09:18 +00:00
|
|
|
|
|
|
|
|
// 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
|
2015-12-14 06:39:33 -08:00
|
|
|
for (; timeStamp <= 250 * 160; timeStamp += 160) {
|
2016-10-05 07:51:44 -07:00
|
|
|
EXPECT_TRUE(module1->SendOutgoingData(
|
|
|
|
|
webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1,
|
|
|
|
|
kTestPayload, 4, nullptr, nullptr, nullptr));
|
2013-01-21 07:42:11 +00:00
|
|
|
fake_clock.AdvanceTimeMilliseconds(20);
|
2012-01-10 14:09:18 +00:00
|
|
|
module1->Process();
|
|
|
|
|
}
|
|
|
|
|
EXPECT_EQ(0, module1->SendTelephoneEventOutband(32, 9000, 10));
|
|
|
|
|
|
2015-12-14 06:39:33 -08:00
|
|
|
for (; timeStamp <= 740 * 160; timeStamp += 160) {
|
2016-10-05 07:51:44 -07:00
|
|
|
EXPECT_TRUE(module1->SendOutgoingData(
|
|
|
|
|
webrtc::kAudioFrameSpeech, kPcmuPayloadType, timeStamp, -1,
|
|
|
|
|
kTestPayload, 4, nullptr, nullptr, nullptr));
|
2013-01-21 07:42:11 +00:00
|
|
|
fake_clock.AdvanceTimeMilliseconds(20);
|
2012-01-10 14:09:18 +00:00
|
|
|
module1->Process();
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-10 12:39:08 -08:00
|
|
|
|
2016-10-05 07:51:44 -07:00
|
|
|
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(×tamp));
|
|
|
|
|
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(×tamp));
|
|
|
|
|
EXPECT_EQ(test_timestamp + in_timestamp, timestamp);
|
|
|
|
|
in_timestamp += 10;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-10 12:39:08 -08:00
|
|
|
} // namespace webrtc
|