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