blob: 607221256e76593a8e0102356e624192ec162752 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/*
12 * This file includes unit tests for NetEQ.
13 */
14
15#include "webrtc/modules/audio_coding/neteq4/interface/neteq.h"
16
17#include <stdlib.h>
18#include <string.h> // memset
19
20#include <string>
21#include <vector>
22
23#include "gtest/gtest.h"
24#include "webrtc/modules/audio_coding/neteq4/test/NETEQTEST_RTPpacket.h"
25#include "webrtc/test/testsupport/fileutils.h"
26#include "webrtc/typedefs.h"
27
28namespace webrtc {
29
30class RefFiles {
31 public:
32 RefFiles(const std::string& input_file, const std::string& output_file);
33 ~RefFiles();
34 template<class T> void ProcessReference(const T& test_results);
35 template<typename T, size_t n> void ProcessReference(
36 const T (&test_results)[n],
37 size_t length);
38 template<typename T, size_t n> void WriteToFile(
39 const T (&test_results)[n],
40 size_t length);
41 template<typename T, size_t n> void ReadFromFileAndCompare(
42 const T (&test_results)[n],
43 size_t length);
44 void WriteToFile(const NetEqNetworkStatistics& stats);
45 void ReadFromFileAndCompare(const NetEqNetworkStatistics& stats);
46 void WriteToFile(const RtcpStatistics& stats);
47 void ReadFromFileAndCompare(const RtcpStatistics& stats);
48
49 FILE* input_fp_;
50 FILE* output_fp_;
51};
52
53RefFiles::RefFiles(const std::string &input_file,
54 const std::string &output_file)
55 : input_fp_(NULL),
56 output_fp_(NULL) {
57 if (!input_file.empty()) {
58 input_fp_ = fopen(input_file.c_str(), "rb");
59 EXPECT_TRUE(input_fp_ != NULL);
60 }
61 if (!output_file.empty()) {
62 output_fp_ = fopen(output_file.c_str(), "wb");
63 EXPECT_TRUE(output_fp_ != NULL);
64 }
65}
66
67RefFiles::~RefFiles() {
68 if (input_fp_) {
69 EXPECT_EQ(EOF, fgetc(input_fp_)); // Make sure that we reached the end.
70 fclose(input_fp_);
71 }
72 if (output_fp_) fclose(output_fp_);
73}
74
75template<class T>
76void RefFiles::ProcessReference(const T& test_results) {
77 WriteToFile(test_results);
78 ReadFromFileAndCompare(test_results);
79}
80
81template<typename T, size_t n>
82void RefFiles::ProcessReference(const T (&test_results)[n], size_t length) {
83 WriteToFile(test_results, length);
84 ReadFromFileAndCompare(test_results, length);
85}
86
87template<typename T, size_t n>
88void RefFiles::WriteToFile(const T (&test_results)[n], size_t length) {
89 if (output_fp_) {
90 ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_));
91 }
92}
93
94template<typename T, size_t n>
95void RefFiles::ReadFromFileAndCompare(const T (&test_results)[n],
96 size_t length) {
97 if (input_fp_) {
98 // Read from ref file.
99 T* ref = new T[length];
100 ASSERT_EQ(length, fread(ref, sizeof(T), length, input_fp_));
101 // Compare
102 ASSERT_EQ(0, memcmp(&test_results, ref, sizeof(T) * length));
103 delete [] ref;
104 }
105}
106
107void RefFiles::WriteToFile(const NetEqNetworkStatistics& stats) {
108 if (output_fp_) {
109 ASSERT_EQ(1u, fwrite(&stats, sizeof(NetEqNetworkStatistics), 1,
110 output_fp_));
111 }
112}
113
114void RefFiles::ReadFromFileAndCompare(
115 const NetEqNetworkStatistics& stats) {
116 if (input_fp_) {
117 // Read from ref file.
118 size_t stat_size = sizeof(NetEqNetworkStatistics);
119 NetEqNetworkStatistics ref_stats;
120 ASSERT_EQ(1u, fread(&ref_stats, stat_size, 1, input_fp_));
121 // Compare
122 EXPECT_EQ(0, memcmp(&stats, &ref_stats, stat_size));
123 }
124}
125
126void RefFiles::WriteToFile(const RtcpStatistics& stats) {
127 if (output_fp_) {
128 ASSERT_EQ(1u, fwrite(&(stats.fraction_lost), sizeof(stats.fraction_lost), 1,
129 output_fp_));
130 ASSERT_EQ(1u, fwrite(&(stats.cumulative_lost),
131 sizeof(stats.cumulative_lost), 1, output_fp_));
132 ASSERT_EQ(1u, fwrite(&(stats.extended_max), sizeof(stats.extended_max), 1,
133 output_fp_));
134 ASSERT_EQ(1u, fwrite(&(stats.jitter), sizeof(stats.jitter), 1,
135 output_fp_));
136 }
137}
138
139void RefFiles::ReadFromFileAndCompare(
140 const RtcpStatistics& stats) {
141 if (input_fp_) {
142 // Read from ref file.
143 RtcpStatistics ref_stats;
144 ASSERT_EQ(1u, fread(&(ref_stats.fraction_lost),
145 sizeof(ref_stats.fraction_lost), 1, input_fp_));
146 ASSERT_EQ(1u, fread(&(ref_stats.cumulative_lost),
147 sizeof(ref_stats.cumulative_lost), 1, input_fp_));
148 ASSERT_EQ(1u, fread(&(ref_stats.extended_max),
149 sizeof(ref_stats.extended_max), 1, input_fp_));
150 ASSERT_EQ(1u, fread(&(ref_stats.jitter), sizeof(ref_stats.jitter), 1,
151 input_fp_));
152 // Compare
153 EXPECT_EQ(ref_stats.fraction_lost, stats.fraction_lost);
154 EXPECT_EQ(ref_stats.cumulative_lost, stats.cumulative_lost);
155 EXPECT_EQ(ref_stats.extended_max, stats.extended_max);
156 EXPECT_EQ(ref_stats.jitter, stats.jitter);
157 }
158}
159
160class NetEqDecodingTest : public ::testing::Test {
161 protected:
162 // NetEQ must be polled for data once every 10 ms. Thus, neither of the
163 // constants below can be changed.
164 static const int kTimeStepMs = 10;
165 static const int kBlockSize8kHz = kTimeStepMs * 8;
166 static const int kBlockSize16kHz = kTimeStepMs * 16;
167 static const int kBlockSize32kHz = kTimeStepMs * 32;
168 static const int kMaxBlockSize = kBlockSize32kHz;
169 static const int kInitSampleRateHz = 8000;
170
171 NetEqDecodingTest();
172 virtual void SetUp();
173 virtual void TearDown();
174 void SelectDecoders(NetEqDecoder* used_codec);
175 void LoadDecoders();
176 void OpenInputFile(const std::string &rtp_file);
177 void Process(NETEQTEST_RTPpacket* rtp_ptr, int* out_len);
178 void DecodeAndCompare(const std::string &rtp_file,
179 const std::string &ref_file);
180 void DecodeAndCheckStats(const std::string &rtp_file,
181 const std::string &stat_ref_file,
182 const std::string &rtcp_ref_file);
183 static void PopulateRtpInfo(int frame_index,
184 int timestamp,
185 WebRtcRTPHeader* rtp_info);
186 static void PopulateCng(int frame_index,
187 int timestamp,
188 WebRtcRTPHeader* rtp_info,
189 uint8_t* payload,
190 int* payload_len);
191
192 NetEq* neteq_;
193 FILE* rtp_fp_;
194 unsigned int sim_clock_;
195 int16_t out_data_[kMaxBlockSize];
196 int output_sample_rate_;
197};
198
199// Allocating the static const so that it can be passed by reference.
200const int NetEqDecodingTest::kTimeStepMs;
201const int NetEqDecodingTest::kBlockSize8kHz;
202const int NetEqDecodingTest::kBlockSize16kHz;
203const int NetEqDecodingTest::kBlockSize32kHz;
204const int NetEqDecodingTest::kMaxBlockSize;
205const int NetEqDecodingTest::kInitSampleRateHz;
206
207NetEqDecodingTest::NetEqDecodingTest()
208 : neteq_(NULL),
209 rtp_fp_(NULL),
210 sim_clock_(0),
211 output_sample_rate_(kInitSampleRateHz) {
212 memset(out_data_, 0, sizeof(out_data_));
213}
214
215void NetEqDecodingTest::SetUp() {
216 neteq_ = NetEq::Create(kInitSampleRateHz);
217 ASSERT_TRUE(neteq_);
218 LoadDecoders();
219}
220
221void NetEqDecodingTest::TearDown() {
222 delete neteq_;
223 if (rtp_fp_)
224 fclose(rtp_fp_);
225}
226
227void NetEqDecodingTest::LoadDecoders() {
228 // Load PCMu.
229 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCMu, 0));
230 // Load PCMa.
231 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCMa, 8));
232 // Load iLBC.
233 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderILBC, 102));
234 // Load iSAC.
235 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISAC, 103));
236 // Load iSAC SWB.
237 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACswb, 104));
henrik.lundin@webrtc.orgac59dba2013-01-31 09:55:24 +0000238 // Load iSAC FB.
239 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACfb, 105));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000240 // Load PCM16B nb.
241 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16B, 93));
242 // Load PCM16B wb.
243 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bwb, 94));
244 // Load PCM16B swb32.
245 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bswb32kHz, 95));
246 // Load CNG 8 kHz.
247 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGnb, 13));
248 // Load CNG 16 kHz.
249 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGwb, 98));
250}
251
252void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
253 rtp_fp_ = fopen(rtp_file.c_str(), "rb");
254 ASSERT_TRUE(rtp_fp_ != NULL);
255 ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp_));
256}
257
258void NetEqDecodingTest::Process(NETEQTEST_RTPpacket* rtp, int* out_len) {
259 // Check if time to receive.
260 while ((sim_clock_ >= rtp->time()) &&
261 (rtp->dataLen() >= 0)) {
262 if (rtp->dataLen() > 0) {
263 WebRtcRTPHeader rtpInfo;
264 rtp->parseHeader(&rtpInfo);
265 ASSERT_EQ(0, neteq_->InsertPacket(
266 rtpInfo,
267 rtp->payload(),
268 rtp->payloadLen(),
269 rtp->time() * (output_sample_rate_ / 1000)));
270 }
271 // Get next packet.
272 ASSERT_NE(-1, rtp->readFromFile(rtp_fp_));
273 }
274
henrik.lundin@webrtc.orge1d468c2013-01-30 07:37:20 +0000275 // Get audio from NetEq.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000276 NetEqOutputType type;
277 int num_channels;
278 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, out_len,
279 &num_channels, &type));
280 ASSERT_TRUE((*out_len == kBlockSize8kHz) ||
281 (*out_len == kBlockSize16kHz) ||
282 (*out_len == kBlockSize32kHz));
283 output_sample_rate_ = *out_len / 10 * 1000;
284
285 // Increase time.
286 sim_clock_ += kTimeStepMs;
287}
288
289void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
290 const std::string &ref_file) {
291 OpenInputFile(rtp_file);
292
293 std::string ref_out_file = "";
294 if (ref_file.empty()) {
295 ref_out_file = webrtc::test::OutputPath() + "neteq_out.pcm";
296 }
297 RefFiles ref_files(ref_file, ref_out_file);
298
299 NETEQTEST_RTPpacket rtp;
300 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
301 int i = 0;
302 while (rtp.dataLen() >= 0) {
303 std::ostringstream ss;
304 ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
305 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
306 int out_len;
307 ASSERT_NO_FATAL_FAILURE(Process(&rtp, &out_len));
308 ASSERT_NO_FATAL_FAILURE(ref_files.ProcessReference(out_data_, out_len));
309 }
310}
311
312void NetEqDecodingTest::DecodeAndCheckStats(const std::string &rtp_file,
313 const std::string &stat_ref_file,
314 const std::string &rtcp_ref_file) {
315 OpenInputFile(rtp_file);
316 std::string stat_out_file = "";
317 if (stat_ref_file.empty()) {
318 stat_out_file = webrtc::test::OutputPath() +
319 "neteq_network_stats.dat";
320 }
321 RefFiles network_stat_files(stat_ref_file, stat_out_file);
322
323 std::string rtcp_out_file = "";
324 if (rtcp_ref_file.empty()) {
325 rtcp_out_file = webrtc::test::OutputPath() +
326 "neteq_rtcp_stats.dat";
327 }
328 RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);
329
330 NETEQTEST_RTPpacket rtp;
331 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
332 while (rtp.dataLen() >= 0) {
333 int out_len;
334 Process(&rtp, &out_len);
335
336 // Query the network statistics API once per second
337 if (sim_clock_ % 1000 == 0) {
338 // Process NetworkStatistics.
339 NetEqNetworkStatistics network_stats;
340 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
341 network_stat_files.ProcessReference(network_stats);
342
343 // Process RTCPstat.
344 RtcpStatistics rtcp_stats;
345 neteq_->GetRtcpStatistics(&rtcp_stats);
346 rtcp_stat_files.ProcessReference(rtcp_stats);
347 }
348 }
349}
350
351void NetEqDecodingTest::PopulateRtpInfo(int frame_index,
352 int timestamp,
353 WebRtcRTPHeader* rtp_info) {
354 rtp_info->header.sequenceNumber = frame_index;
355 rtp_info->header.timestamp = timestamp;
356 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
357 rtp_info->header.payloadType = 94; // PCM16b WB codec.
358 rtp_info->header.markerBit = 0;
359}
360
361void NetEqDecodingTest::PopulateCng(int frame_index,
362 int timestamp,
363 WebRtcRTPHeader* rtp_info,
364 uint8_t* payload,
365 int* payload_len) {
366 rtp_info->header.sequenceNumber = frame_index;
367 rtp_info->header.timestamp = timestamp;
368 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
369 rtp_info->header.payloadType = 98; // WB CNG.
370 rtp_info->header.markerBit = 0;
371 payload[0] = 64; // Noise level -64 dBov, quite arbitrarily chosen.
372 *payload_len = 1; // Only noise level, no spectral parameters.
373}
374
kjellander@webrtc.org6eba2772013-06-04 05:46:37 +0000375#if defined(_WIN32) && defined(WEBRTC_ARCH_64_BITS)
376// Disabled for Windows 64-bit until webrtc:1458 is fixed.
377#define MAYBE_TestBitExactness DISABLED_TestBitExactness
378#else
379#define MAYBE_TestBitExactness TestBitExactness
380#endif
381
382TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000383 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000384 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000385#if defined(_MSC_VER) && (_MSC_VER >= 1700)
386 // For Visual Studio 2012 and later, we will have to use the generic reference
387 // file, rather than the windows-specific one.
388 const std::string kInputRefFile = webrtc::test::ProjectRootPath() +
389 "resources/audio_coding/neteq_universal_ref.pcm";
390#else
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000391 const std::string kInputRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000392 webrtc::test::ResourcePath("audio_coding/neteq_universal_ref", "pcm");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000393#endif
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000394 DecodeAndCompare(kInputRtpFile, kInputRefFile);
395}
396
henrik.lundin@webrtc.org48924482013-01-30 09:57:33 +0000397TEST_F(NetEqDecodingTest, TestNetworkStatistics) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000398 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000399 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000400#if defined(_MSC_VER) && (_MSC_VER >= 1700)
401 // For Visual Studio 2012 and later, we will have to use the generic reference
402 // file, rather than the windows-specific one.
403 const std::string kNetworkStatRefFile = webrtc::test::ProjectRootPath() +
404 "resources/audio_coding/neteq_network_stats.dat";
405#else
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000406 const std::string kNetworkStatRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000407 webrtc::test::ResourcePath("audio_coding/neteq_network_stats", "dat");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000408#endif
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000409 const std::string kRtcpStatRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000410 webrtc::test::ResourcePath("audio_coding/neteq_rtcp_stats", "dat");
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000411 DecodeAndCheckStats(kInputRtpFile, kNetworkStatRefFile, kRtcpStatRefFile);
412}
413
414// TODO(hlundin): Re-enable test once the statistics interface is up and again.
415TEST_F(NetEqDecodingTest, TestFrameWaitingTimeStatistics) {
416 // Use fax mode to avoid time-scaling. This is to simplify the testing of
417 // packet waiting times in the packet buffer.
418 neteq_->SetPlayoutMode(kPlayoutFax);
419 ASSERT_EQ(kPlayoutFax, neteq_->PlayoutMode());
420 // Insert 30 dummy packets at once. Each packet contains 10 ms 16 kHz audio.
421 size_t num_frames = 30;
422 const int kSamples = 10 * 16;
423 const int kPayloadBytes = kSamples * 2;
424 for (size_t i = 0; i < num_frames; ++i) {
425 uint16_t payload[kSamples] = {0};
426 WebRtcRTPHeader rtp_info;
427 rtp_info.header.sequenceNumber = i;
428 rtp_info.header.timestamp = i * kSamples;
429 rtp_info.header.ssrc = 0x1234; // Just an arbitrary SSRC.
430 rtp_info.header.payloadType = 94; // PCM16b WB codec.
431 rtp_info.header.markerBit = 0;
432 ASSERT_EQ(0, neteq_->InsertPacket(
433 rtp_info,
434 reinterpret_cast<uint8_t*>(payload),
435 kPayloadBytes, 0));
436 }
437 // Pull out all data.
438 for (size_t i = 0; i < num_frames; ++i) {
439 int out_len;
440 int num_channels;
441 NetEqOutputType type;
442 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
443 &num_channels, &type));
444 ASSERT_EQ(kBlockSize16kHz, out_len);
445 }
446
447 std::vector<int> waiting_times;
448 neteq_->WaitingTimes(&waiting_times);
449 int len = waiting_times.size();
450 EXPECT_EQ(num_frames, waiting_times.size());
451 // Since all frames are dumped into NetEQ at once, but pulled out with 10 ms
452 // spacing (per definition), we expect the delay to increase with 10 ms for
453 // each packet.
454 for (size_t i = 0; i < waiting_times.size(); ++i) {
455 EXPECT_EQ(static_cast<int>(i + 1) * 10, waiting_times[i]);
456 }
457
458 // Check statistics again and make sure it's been reset.
459 neteq_->WaitingTimes(&waiting_times);
460 len = waiting_times.size();
461 EXPECT_EQ(0, len);
462
463 // Process > 100 frames, and make sure that that we get statistics
464 // only for 100 frames. Note the new SSRC, causing NetEQ to reset.
465 num_frames = 110;
466 for (size_t i = 0; i < num_frames; ++i) {
467 uint16_t payload[kSamples] = {0};
468 WebRtcRTPHeader rtp_info;
469 rtp_info.header.sequenceNumber = i;
470 rtp_info.header.timestamp = i * kSamples;
471 rtp_info.header.ssrc = 0x1235; // Just an arbitrary SSRC.
472 rtp_info.header.payloadType = 94; // PCM16b WB codec.
473 rtp_info.header.markerBit = 0;
474 ASSERT_EQ(0, neteq_->InsertPacket(
475 rtp_info,
476 reinterpret_cast<uint8_t*>(payload),
477 kPayloadBytes, 0));
478 int out_len;
479 int num_channels;
480 NetEqOutputType type;
481 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
482 &num_channels, &type));
483 ASSERT_EQ(kBlockSize16kHz, out_len);
484 }
485
486 neteq_->WaitingTimes(&waiting_times);
487 EXPECT_EQ(100u, waiting_times.size());
488}
489
490TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimeNegative) {
491 const int kNumFrames = 3000; // Needed for convergence.
492 int frame_index = 0;
493 const int kSamples = 10 * 16;
494 const int kPayloadBytes = kSamples * 2;
495 while (frame_index < kNumFrames) {
496 // Insert one packet each time, except every 10th time where we insert two
497 // packets at once. This will create a negative clock-drift of approx. 10%.
498 int num_packets = (frame_index % 10 == 0 ? 2 : 1);
499 for (int n = 0; n < num_packets; ++n) {
500 uint8_t payload[kPayloadBytes] = {0};
501 WebRtcRTPHeader rtp_info;
502 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
503 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
504 ++frame_index;
505 }
506
507 // Pull out data once.
508 int out_len;
509 int num_channels;
510 NetEqOutputType type;
511 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
512 &num_channels, &type));
513 ASSERT_EQ(kBlockSize16kHz, out_len);
514 }
515
516 NetEqNetworkStatistics network_stats;
517 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
518 EXPECT_EQ(-103196, network_stats.clockdrift_ppm);
519}
520
521TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimePositive) {
522 const int kNumFrames = 5000; // Needed for convergence.
523 int frame_index = 0;
524 const int kSamples = 10 * 16;
525 const int kPayloadBytes = kSamples * 2;
526 for (int i = 0; i < kNumFrames; ++i) {
527 // Insert one packet each time, except every 10th time where we don't insert
528 // any packet. This will create a positive clock-drift of approx. 11%.
529 int num_packets = (i % 10 == 9 ? 0 : 1);
530 for (int n = 0; n < num_packets; ++n) {
531 uint8_t payload[kPayloadBytes] = {0};
532 WebRtcRTPHeader rtp_info;
533 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
534 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
535 ++frame_index;
536 }
537
538 // Pull out data once.
539 int out_len;
540 int num_channels;
541 NetEqOutputType type;
542 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
543 &num_channels, &type));
544 ASSERT_EQ(kBlockSize16kHz, out_len);
545 }
546
547 NetEqNetworkStatistics network_stats;
548 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
549 EXPECT_EQ(110946, network_stats.clockdrift_ppm);
550}
551
552TEST_F(NetEqDecodingTest, LongCngWithClockDrift) {
553 uint16_t seq_no = 0;
554 uint32_t timestamp = 0;
555 const int kFrameSizeMs = 30;
556 const int kSamples = kFrameSizeMs * 16;
557 const int kPayloadBytes = kSamples * 2;
558 // Apply a clock drift of -25 ms / s (sender faster than receiver).
559 const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
560 double next_input_time_ms = 0.0;
561 double t_ms;
562 NetEqOutputType type;
563
564 // Insert speech for 5 seconds.
565 const int kSpeechDurationMs = 5000;
566 for (t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
567 // Each turn in this for loop is 10 ms.
568 while (next_input_time_ms <= t_ms) {
569 // Insert one 30 ms speech frame.
570 uint8_t payload[kPayloadBytes] = {0};
571 WebRtcRTPHeader rtp_info;
572 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
573 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
574 ++seq_no;
575 timestamp += kSamples;
576 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
577 }
578 // Pull out data once.
579 int out_len;
580 int num_channels;
581 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
582 &num_channels, &type));
583 ASSERT_EQ(kBlockSize16kHz, out_len);
584 }
585
586 EXPECT_EQ(kOutputNormal, type);
587 int32_t delay_before = timestamp - neteq_->PlayoutTimestamp();
588
589 // Insert CNG for 1 minute (= 60000 ms).
590 const int kCngPeriodMs = 100;
591 const int kCngPeriodSamples = kCngPeriodMs * 16; // Period in 16 kHz samples.
592 const int kCngDurationMs = 60000;
593 for (; t_ms < kSpeechDurationMs + kCngDurationMs; t_ms += 10) {
594 // Each turn in this for loop is 10 ms.
595 while (next_input_time_ms <= t_ms) {
596 // Insert one CNG frame each 100 ms.
597 uint8_t payload[kPayloadBytes];
598 int payload_len;
599 WebRtcRTPHeader rtp_info;
600 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
601 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
602 ++seq_no;
603 timestamp += kCngPeriodSamples;
604 next_input_time_ms += static_cast<double>(kCngPeriodMs) * kDriftFactor;
605 }
606 // Pull out data once.
607 int out_len;
608 int num_channels;
609 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
610 &num_channels, &type));
611 ASSERT_EQ(kBlockSize16kHz, out_len);
612 }
613
614 EXPECT_EQ(kOutputCNG, type);
615
616 // Insert speech again until output type is speech.
617 while (type != kOutputNormal) {
618 // Each turn in this for loop is 10 ms.
619 while (next_input_time_ms <= t_ms) {
620 // Insert one 30 ms speech frame.
621 uint8_t payload[kPayloadBytes] = {0};
622 WebRtcRTPHeader rtp_info;
623 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
624 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
625 ++seq_no;
626 timestamp += kSamples;
627 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
628 }
629 // Pull out data once.
630 int out_len;
631 int num_channels;
632 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
633 &num_channels, &type));
634 ASSERT_EQ(kBlockSize16kHz, out_len);
635 // Increase clock.
636 t_ms += 10;
637 }
638
639 int32_t delay_after = timestamp - neteq_->PlayoutTimestamp();
640 // Compare delay before and after, and make sure it differs less than 20 ms.
641 EXPECT_LE(delay_after, delay_before + 20 * 16);
642 EXPECT_GE(delay_after, delay_before - 20 * 16);
643}
644
645TEST_F(NetEqDecodingTest, UnknownPayloadType) {
646 const int kPayloadBytes = 100;
647 uint8_t payload[kPayloadBytes] = {0};
648 WebRtcRTPHeader rtp_info;
649 PopulateRtpInfo(0, 0, &rtp_info);
650 rtp_info.header.payloadType = 1; // Not registered as a decoder.
651 EXPECT_EQ(NetEq::kFail,
652 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
653 EXPECT_EQ(NetEq::kUnknownRtpPayloadType, neteq_->LastError());
654}
655
656TEST_F(NetEqDecodingTest, DecoderError) {
657 const int kPayloadBytes = 100;
658 uint8_t payload[kPayloadBytes] = {0};
659 WebRtcRTPHeader rtp_info;
660 PopulateRtpInfo(0, 0, &rtp_info);
661 rtp_info.header.payloadType = 103; // iSAC, but the payload is invalid.
662 EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
663 NetEqOutputType type;
664 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
665 // to GetAudio.
666 for (int i = 0; i < kMaxBlockSize; ++i) {
667 out_data_[i] = 1;
668 }
669 int num_channels;
670 int samples_per_channel;
671 EXPECT_EQ(NetEq::kFail,
672 neteq_->GetAudio(kMaxBlockSize, out_data_,
673 &samples_per_channel, &num_channels, &type));
674 // Verify that there is a decoder error to check.
675 EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
676 // Code 6730 is an iSAC error code.
677 EXPECT_EQ(6730, neteq_->LastDecoderError());
678 // Verify that the first 160 samples are set to 0, and that the remaining
679 // samples are left unmodified.
680 static const int kExpectedOutputLength = 160; // 10 ms at 16 kHz sample rate.
681 for (int i = 0; i < kExpectedOutputLength; ++i) {
682 std::ostringstream ss;
683 ss << "i = " << i;
684 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
685 EXPECT_EQ(0, out_data_[i]);
686 }
687 for (int i = kExpectedOutputLength; i < kMaxBlockSize; ++i) {
688 std::ostringstream ss;
689 ss << "i = " << i;
690 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
691 EXPECT_EQ(1, out_data_[i]);
692 }
693}
694
695TEST_F(NetEqDecodingTest, GetAudioBeforeInsertPacket) {
696 NetEqOutputType type;
697 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
698 // to GetAudio.
699 for (int i = 0; i < kMaxBlockSize; ++i) {
700 out_data_[i] = 1;
701 }
702 int num_channels;
703 int samples_per_channel;
704 EXPECT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_,
705 &samples_per_channel,
706 &num_channels, &type));
707 // Verify that the first block of samples is set to 0.
708 static const int kExpectedOutputLength =
709 kInitSampleRateHz / 100; // 10 ms at initial sample rate.
710 for (int i = 0; i < kExpectedOutputLength; ++i) {
711 std::ostringstream ss;
712 ss << "i = " << i;
713 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
714 EXPECT_EQ(0, out_data_[i]);
715 }
716}
717} // namespace