blob: 29e2f3f81e085ae57470a99014b56a509f4c2361 [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
henrik.lundin@webrtc.org48924482013-01-30 09:57:33 +0000375TEST_F(NetEqDecodingTest, TestBitExactness) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000376 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000377 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000378#if defined(_MSC_VER) && (_MSC_VER >= 1700)
379 // For Visual Studio 2012 and later, we will have to use the generic reference
380 // file, rather than the windows-specific one.
381 const std::string kInputRefFile = webrtc::test::ProjectRootPath() +
382 "resources/audio_coding/neteq_universal_ref.pcm";
383#else
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000384 const std::string kInputRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000385 webrtc::test::ResourcePath("audio_coding/neteq_universal_ref", "pcm");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000386#endif
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000387 DecodeAndCompare(kInputRtpFile, kInputRefFile);
388}
389
henrik.lundin@webrtc.org48924482013-01-30 09:57:33 +0000390TEST_F(NetEqDecodingTest, TestNetworkStatistics) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000391 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000392 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000393#if defined(_MSC_VER) && (_MSC_VER >= 1700)
394 // For Visual Studio 2012 and later, we will have to use the generic reference
395 // file, rather than the windows-specific one.
396 const std::string kNetworkStatRefFile = webrtc::test::ProjectRootPath() +
397 "resources/audio_coding/neteq_network_stats.dat";
398#else
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000399 const std::string kNetworkStatRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000400 webrtc::test::ResourcePath("audio_coding/neteq_network_stats", "dat");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000401#endif
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000402 const std::string kRtcpStatRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000403 webrtc::test::ResourcePath("audio_coding/neteq_rtcp_stats", "dat");
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000404 DecodeAndCheckStats(kInputRtpFile, kNetworkStatRefFile, kRtcpStatRefFile);
405}
406
407// TODO(hlundin): Re-enable test once the statistics interface is up and again.
408TEST_F(NetEqDecodingTest, TestFrameWaitingTimeStatistics) {
409 // Use fax mode to avoid time-scaling. This is to simplify the testing of
410 // packet waiting times in the packet buffer.
411 neteq_->SetPlayoutMode(kPlayoutFax);
412 ASSERT_EQ(kPlayoutFax, neteq_->PlayoutMode());
413 // Insert 30 dummy packets at once. Each packet contains 10 ms 16 kHz audio.
414 size_t num_frames = 30;
415 const int kSamples = 10 * 16;
416 const int kPayloadBytes = kSamples * 2;
417 for (size_t i = 0; i < num_frames; ++i) {
418 uint16_t payload[kSamples] = {0};
419 WebRtcRTPHeader rtp_info;
420 rtp_info.header.sequenceNumber = i;
421 rtp_info.header.timestamp = i * kSamples;
422 rtp_info.header.ssrc = 0x1234; // Just an arbitrary SSRC.
423 rtp_info.header.payloadType = 94; // PCM16b WB codec.
424 rtp_info.header.markerBit = 0;
425 ASSERT_EQ(0, neteq_->InsertPacket(
426 rtp_info,
427 reinterpret_cast<uint8_t*>(payload),
428 kPayloadBytes, 0));
429 }
430 // Pull out all data.
431 for (size_t i = 0; i < num_frames; ++i) {
432 int out_len;
433 int num_channels;
434 NetEqOutputType type;
435 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
436 &num_channels, &type));
437 ASSERT_EQ(kBlockSize16kHz, out_len);
438 }
439
440 std::vector<int> waiting_times;
441 neteq_->WaitingTimes(&waiting_times);
442 int len = waiting_times.size();
443 EXPECT_EQ(num_frames, waiting_times.size());
444 // Since all frames are dumped into NetEQ at once, but pulled out with 10 ms
445 // spacing (per definition), we expect the delay to increase with 10 ms for
446 // each packet.
447 for (size_t i = 0; i < waiting_times.size(); ++i) {
448 EXPECT_EQ(static_cast<int>(i + 1) * 10, waiting_times[i]);
449 }
450
451 // Check statistics again and make sure it's been reset.
452 neteq_->WaitingTimes(&waiting_times);
453 len = waiting_times.size();
454 EXPECT_EQ(0, len);
455
456 // Process > 100 frames, and make sure that that we get statistics
457 // only for 100 frames. Note the new SSRC, causing NetEQ to reset.
458 num_frames = 110;
459 for (size_t i = 0; i < num_frames; ++i) {
460 uint16_t payload[kSamples] = {0};
461 WebRtcRTPHeader rtp_info;
462 rtp_info.header.sequenceNumber = i;
463 rtp_info.header.timestamp = i * kSamples;
464 rtp_info.header.ssrc = 0x1235; // Just an arbitrary SSRC.
465 rtp_info.header.payloadType = 94; // PCM16b WB codec.
466 rtp_info.header.markerBit = 0;
467 ASSERT_EQ(0, neteq_->InsertPacket(
468 rtp_info,
469 reinterpret_cast<uint8_t*>(payload),
470 kPayloadBytes, 0));
471 int out_len;
472 int num_channels;
473 NetEqOutputType type;
474 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
475 &num_channels, &type));
476 ASSERT_EQ(kBlockSize16kHz, out_len);
477 }
478
479 neteq_->WaitingTimes(&waiting_times);
480 EXPECT_EQ(100u, waiting_times.size());
481}
482
483TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimeNegative) {
484 const int kNumFrames = 3000; // Needed for convergence.
485 int frame_index = 0;
486 const int kSamples = 10 * 16;
487 const int kPayloadBytes = kSamples * 2;
488 while (frame_index < kNumFrames) {
489 // Insert one packet each time, except every 10th time where we insert two
490 // packets at once. This will create a negative clock-drift of approx. 10%.
491 int num_packets = (frame_index % 10 == 0 ? 2 : 1);
492 for (int n = 0; n < num_packets; ++n) {
493 uint8_t payload[kPayloadBytes] = {0};
494 WebRtcRTPHeader rtp_info;
495 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
496 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
497 ++frame_index;
498 }
499
500 // Pull out data once.
501 int out_len;
502 int num_channels;
503 NetEqOutputType type;
504 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
505 &num_channels, &type));
506 ASSERT_EQ(kBlockSize16kHz, out_len);
507 }
508
509 NetEqNetworkStatistics network_stats;
510 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
511 EXPECT_EQ(-103196, network_stats.clockdrift_ppm);
512}
513
514TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimePositive) {
515 const int kNumFrames = 5000; // Needed for convergence.
516 int frame_index = 0;
517 const int kSamples = 10 * 16;
518 const int kPayloadBytes = kSamples * 2;
519 for (int i = 0; i < kNumFrames; ++i) {
520 // Insert one packet each time, except every 10th time where we don't insert
521 // any packet. This will create a positive clock-drift of approx. 11%.
522 int num_packets = (i % 10 == 9 ? 0 : 1);
523 for (int n = 0; n < num_packets; ++n) {
524 uint8_t payload[kPayloadBytes] = {0};
525 WebRtcRTPHeader rtp_info;
526 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
527 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
528 ++frame_index;
529 }
530
531 // Pull out data once.
532 int out_len;
533 int num_channels;
534 NetEqOutputType type;
535 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
536 &num_channels, &type));
537 ASSERT_EQ(kBlockSize16kHz, out_len);
538 }
539
540 NetEqNetworkStatistics network_stats;
541 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
542 EXPECT_EQ(110946, network_stats.clockdrift_ppm);
543}
544
545TEST_F(NetEqDecodingTest, LongCngWithClockDrift) {
546 uint16_t seq_no = 0;
547 uint32_t timestamp = 0;
548 const int kFrameSizeMs = 30;
549 const int kSamples = kFrameSizeMs * 16;
550 const int kPayloadBytes = kSamples * 2;
551 // Apply a clock drift of -25 ms / s (sender faster than receiver).
552 const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
553 double next_input_time_ms = 0.0;
554 double t_ms;
555 NetEqOutputType type;
556
557 // Insert speech for 5 seconds.
558 const int kSpeechDurationMs = 5000;
559 for (t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
560 // Each turn in this for loop is 10 ms.
561 while (next_input_time_ms <= t_ms) {
562 // Insert one 30 ms speech frame.
563 uint8_t payload[kPayloadBytes] = {0};
564 WebRtcRTPHeader rtp_info;
565 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
566 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
567 ++seq_no;
568 timestamp += kSamples;
569 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
570 }
571 // Pull out data once.
572 int out_len;
573 int num_channels;
574 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
575 &num_channels, &type));
576 ASSERT_EQ(kBlockSize16kHz, out_len);
577 }
578
579 EXPECT_EQ(kOutputNormal, type);
580 int32_t delay_before = timestamp - neteq_->PlayoutTimestamp();
581
582 // Insert CNG for 1 minute (= 60000 ms).
583 const int kCngPeriodMs = 100;
584 const int kCngPeriodSamples = kCngPeriodMs * 16; // Period in 16 kHz samples.
585 const int kCngDurationMs = 60000;
586 for (; t_ms < kSpeechDurationMs + kCngDurationMs; t_ms += 10) {
587 // Each turn in this for loop is 10 ms.
588 while (next_input_time_ms <= t_ms) {
589 // Insert one CNG frame each 100 ms.
590 uint8_t payload[kPayloadBytes];
591 int payload_len;
592 WebRtcRTPHeader rtp_info;
593 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
594 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
595 ++seq_no;
596 timestamp += kCngPeriodSamples;
597 next_input_time_ms += static_cast<double>(kCngPeriodMs) * kDriftFactor;
598 }
599 // Pull out data once.
600 int out_len;
601 int num_channels;
602 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
603 &num_channels, &type));
604 ASSERT_EQ(kBlockSize16kHz, out_len);
605 }
606
607 EXPECT_EQ(kOutputCNG, type);
608
609 // Insert speech again until output type is speech.
610 while (type != kOutputNormal) {
611 // Each turn in this for loop is 10 ms.
612 while (next_input_time_ms <= t_ms) {
613 // Insert one 30 ms speech frame.
614 uint8_t payload[kPayloadBytes] = {0};
615 WebRtcRTPHeader rtp_info;
616 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
617 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
618 ++seq_no;
619 timestamp += kSamples;
620 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
621 }
622 // Pull out data once.
623 int out_len;
624 int num_channels;
625 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
626 &num_channels, &type));
627 ASSERT_EQ(kBlockSize16kHz, out_len);
628 // Increase clock.
629 t_ms += 10;
630 }
631
632 int32_t delay_after = timestamp - neteq_->PlayoutTimestamp();
633 // Compare delay before and after, and make sure it differs less than 20 ms.
634 EXPECT_LE(delay_after, delay_before + 20 * 16);
635 EXPECT_GE(delay_after, delay_before - 20 * 16);
636}
637
638TEST_F(NetEqDecodingTest, UnknownPayloadType) {
639 const int kPayloadBytes = 100;
640 uint8_t payload[kPayloadBytes] = {0};
641 WebRtcRTPHeader rtp_info;
642 PopulateRtpInfo(0, 0, &rtp_info);
643 rtp_info.header.payloadType = 1; // Not registered as a decoder.
644 EXPECT_EQ(NetEq::kFail,
645 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
646 EXPECT_EQ(NetEq::kUnknownRtpPayloadType, neteq_->LastError());
647}
648
649TEST_F(NetEqDecodingTest, DecoderError) {
650 const int kPayloadBytes = 100;
651 uint8_t payload[kPayloadBytes] = {0};
652 WebRtcRTPHeader rtp_info;
653 PopulateRtpInfo(0, 0, &rtp_info);
654 rtp_info.header.payloadType = 103; // iSAC, but the payload is invalid.
655 EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
656 NetEqOutputType type;
657 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
658 // to GetAudio.
659 for (int i = 0; i < kMaxBlockSize; ++i) {
660 out_data_[i] = 1;
661 }
662 int num_channels;
663 int samples_per_channel;
664 EXPECT_EQ(NetEq::kFail,
665 neteq_->GetAudio(kMaxBlockSize, out_data_,
666 &samples_per_channel, &num_channels, &type));
667 // Verify that there is a decoder error to check.
668 EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
669 // Code 6730 is an iSAC error code.
670 EXPECT_EQ(6730, neteq_->LastDecoderError());
671 // Verify that the first 160 samples are set to 0, and that the remaining
672 // samples are left unmodified.
673 static const int kExpectedOutputLength = 160; // 10 ms at 16 kHz sample rate.
674 for (int i = 0; i < kExpectedOutputLength; ++i) {
675 std::ostringstream ss;
676 ss << "i = " << i;
677 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
678 EXPECT_EQ(0, out_data_[i]);
679 }
680 for (int i = kExpectedOutputLength; i < kMaxBlockSize; ++i) {
681 std::ostringstream ss;
682 ss << "i = " << i;
683 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
684 EXPECT_EQ(1, out_data_[i]);
685 }
686}
687
688TEST_F(NetEqDecodingTest, GetAudioBeforeInsertPacket) {
689 NetEqOutputType type;
690 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
691 // to GetAudio.
692 for (int i = 0; i < kMaxBlockSize; ++i) {
693 out_data_[i] = 1;
694 }
695 int num_channels;
696 int samples_per_channel;
697 EXPECT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_,
698 &samples_per_channel,
699 &num_channels, &type));
700 // Verify that the first block of samples is set to 0.
701 static const int kExpectedOutputLength =
702 kInitSampleRateHz / 100; // 10 ms at initial sample rate.
703 for (int i = 0; i < kExpectedOutputLength; ++i) {
704 std::ostringstream ss;
705 ss << "i = " << i;
706 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
707 EXPECT_EQ(0, out_data_[i]);
708 }
709}
710} // namespace