blob: c5b44d883a5f4483baf5c2098a3ee88797f16377 [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));
238 // Load PCM16B nb.
239 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16B, 93));
240 // Load PCM16B wb.
241 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bwb, 94));
242 // Load PCM16B swb32.
243 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bswb32kHz, 95));
244 // Load CNG 8 kHz.
245 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGnb, 13));
246 // Load CNG 16 kHz.
247 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGwb, 98));
248}
249
250void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
251 rtp_fp_ = fopen(rtp_file.c_str(), "rb");
252 ASSERT_TRUE(rtp_fp_ != NULL);
253 ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp_));
254}
255
256void NetEqDecodingTest::Process(NETEQTEST_RTPpacket* rtp, int* out_len) {
257 // Check if time to receive.
258 while ((sim_clock_ >= rtp->time()) &&
259 (rtp->dataLen() >= 0)) {
260 if (rtp->dataLen() > 0) {
261 WebRtcRTPHeader rtpInfo;
262 rtp->parseHeader(&rtpInfo);
263 ASSERT_EQ(0, neteq_->InsertPacket(
264 rtpInfo,
265 rtp->payload(),
266 rtp->payloadLen(),
267 rtp->time() * (output_sample_rate_ / 1000)));
268 }
269 // Get next packet.
270 ASSERT_NE(-1, rtp->readFromFile(rtp_fp_));
271 }
272
273 // RecOut
274 NetEqOutputType type;
275 int num_channels;
276 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, out_len,
277 &num_channels, &type));
278 ASSERT_TRUE((*out_len == kBlockSize8kHz) ||
279 (*out_len == kBlockSize16kHz) ||
280 (*out_len == kBlockSize32kHz));
281 output_sample_rate_ = *out_len / 10 * 1000;
282
283 // Increase time.
284 sim_clock_ += kTimeStepMs;
285}
286
287void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
288 const std::string &ref_file) {
289 OpenInputFile(rtp_file);
290
291 std::string ref_out_file = "";
292 if (ref_file.empty()) {
293 ref_out_file = webrtc::test::OutputPath() + "neteq_out.pcm";
294 }
295 RefFiles ref_files(ref_file, ref_out_file);
296
297 NETEQTEST_RTPpacket rtp;
298 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
299 int i = 0;
300 while (rtp.dataLen() >= 0) {
301 std::ostringstream ss;
302 ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
303 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
304 int out_len;
305 ASSERT_NO_FATAL_FAILURE(Process(&rtp, &out_len));
306 ASSERT_NO_FATAL_FAILURE(ref_files.ProcessReference(out_data_, out_len));
307 }
308}
309
310void NetEqDecodingTest::DecodeAndCheckStats(const std::string &rtp_file,
311 const std::string &stat_ref_file,
312 const std::string &rtcp_ref_file) {
313 OpenInputFile(rtp_file);
314 std::string stat_out_file = "";
315 if (stat_ref_file.empty()) {
316 stat_out_file = webrtc::test::OutputPath() +
317 "neteq_network_stats.dat";
318 }
319 RefFiles network_stat_files(stat_ref_file, stat_out_file);
320
321 std::string rtcp_out_file = "";
322 if (rtcp_ref_file.empty()) {
323 rtcp_out_file = webrtc::test::OutputPath() +
324 "neteq_rtcp_stats.dat";
325 }
326 RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);
327
328 NETEQTEST_RTPpacket rtp;
329 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
330 while (rtp.dataLen() >= 0) {
331 int out_len;
332 Process(&rtp, &out_len);
333
334 // Query the network statistics API once per second
335 if (sim_clock_ % 1000 == 0) {
336 // Process NetworkStatistics.
337 NetEqNetworkStatistics network_stats;
338 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
339 network_stat_files.ProcessReference(network_stats);
340
341 // Process RTCPstat.
342 RtcpStatistics rtcp_stats;
343 neteq_->GetRtcpStatistics(&rtcp_stats);
344 rtcp_stat_files.ProcessReference(rtcp_stats);
345 }
346 }
347}
348
349void NetEqDecodingTest::PopulateRtpInfo(int frame_index,
350 int timestamp,
351 WebRtcRTPHeader* rtp_info) {
352 rtp_info->header.sequenceNumber = frame_index;
353 rtp_info->header.timestamp = timestamp;
354 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
355 rtp_info->header.payloadType = 94; // PCM16b WB codec.
356 rtp_info->header.markerBit = 0;
357}
358
359void NetEqDecodingTest::PopulateCng(int frame_index,
360 int timestamp,
361 WebRtcRTPHeader* rtp_info,
362 uint8_t* payload,
363 int* payload_len) {
364 rtp_info->header.sequenceNumber = frame_index;
365 rtp_info->header.timestamp = timestamp;
366 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
367 rtp_info->header.payloadType = 98; // WB CNG.
368 rtp_info->header.markerBit = 0;
369 payload[0] = 64; // Noise level -64 dBov, quite arbitrarily chosen.
370 *payload_len = 1; // Only noise level, no spectral parameters.
371}
372
373TEST_F(NetEqDecodingTest, TestBitExactness) {
374 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
375 "resources/neteq_universal.rtp";
376 const std::string kInputRefFile =
377 webrtc::test::ResourcePath("neteq_universal_ref", "pcm");
378 DecodeAndCompare(kInputRtpFile, kInputRefFile);
379}
380
381TEST_F(NetEqDecodingTest, TestNetworkStatistics) {
382 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
383 "resources/neteq_universal.rtp";
384 const std::string kNetworkStatRefFile =
385 webrtc::test::ResourcePath("neteq_network_stats", "dat");
386 const std::string kRtcpStatRefFile =
387 webrtc::test::ResourcePath("neteq_rtcp_stats", "dat");
388 DecodeAndCheckStats(kInputRtpFile, kNetworkStatRefFile, kRtcpStatRefFile);
389}
390
391// TODO(hlundin): Re-enable test once the statistics interface is up and again.
392TEST_F(NetEqDecodingTest, TestFrameWaitingTimeStatistics) {
393 // Use fax mode to avoid time-scaling. This is to simplify the testing of
394 // packet waiting times in the packet buffer.
395 neteq_->SetPlayoutMode(kPlayoutFax);
396 ASSERT_EQ(kPlayoutFax, neteq_->PlayoutMode());
397 // Insert 30 dummy packets at once. Each packet contains 10 ms 16 kHz audio.
398 size_t num_frames = 30;
399 const int kSamples = 10 * 16;
400 const int kPayloadBytes = kSamples * 2;
401 for (size_t i = 0; i < num_frames; ++i) {
402 uint16_t payload[kSamples] = {0};
403 WebRtcRTPHeader rtp_info;
404 rtp_info.header.sequenceNumber = i;
405 rtp_info.header.timestamp = i * kSamples;
406 rtp_info.header.ssrc = 0x1234; // Just an arbitrary SSRC.
407 rtp_info.header.payloadType = 94; // PCM16b WB codec.
408 rtp_info.header.markerBit = 0;
409 ASSERT_EQ(0, neteq_->InsertPacket(
410 rtp_info,
411 reinterpret_cast<uint8_t*>(payload),
412 kPayloadBytes, 0));
413 }
414 // Pull out all data.
415 for (size_t i = 0; i < num_frames; ++i) {
416 int out_len;
417 int num_channels;
418 NetEqOutputType type;
419 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
420 &num_channels, &type));
421 ASSERT_EQ(kBlockSize16kHz, out_len);
422 }
423
424 std::vector<int> waiting_times;
425 neteq_->WaitingTimes(&waiting_times);
426 int len = waiting_times.size();
427 EXPECT_EQ(num_frames, waiting_times.size());
428 // Since all frames are dumped into NetEQ at once, but pulled out with 10 ms
429 // spacing (per definition), we expect the delay to increase with 10 ms for
430 // each packet.
431 for (size_t i = 0; i < waiting_times.size(); ++i) {
432 EXPECT_EQ(static_cast<int>(i + 1) * 10, waiting_times[i]);
433 }
434
435 // Check statistics again and make sure it's been reset.
436 neteq_->WaitingTimes(&waiting_times);
437 len = waiting_times.size();
438 EXPECT_EQ(0, len);
439
440 // Process > 100 frames, and make sure that that we get statistics
441 // only for 100 frames. Note the new SSRC, causing NetEQ to reset.
442 num_frames = 110;
443 for (size_t i = 0; i < num_frames; ++i) {
444 uint16_t payload[kSamples] = {0};
445 WebRtcRTPHeader rtp_info;
446 rtp_info.header.sequenceNumber = i;
447 rtp_info.header.timestamp = i * kSamples;
448 rtp_info.header.ssrc = 0x1235; // Just an arbitrary SSRC.
449 rtp_info.header.payloadType = 94; // PCM16b WB codec.
450 rtp_info.header.markerBit = 0;
451 ASSERT_EQ(0, neteq_->InsertPacket(
452 rtp_info,
453 reinterpret_cast<uint8_t*>(payload),
454 kPayloadBytes, 0));
455 int out_len;
456 int num_channels;
457 NetEqOutputType type;
458 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
459 &num_channels, &type));
460 ASSERT_EQ(kBlockSize16kHz, out_len);
461 }
462
463 neteq_->WaitingTimes(&waiting_times);
464 EXPECT_EQ(100u, waiting_times.size());
465}
466
467TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimeNegative) {
468 const int kNumFrames = 3000; // Needed for convergence.
469 int frame_index = 0;
470 const int kSamples = 10 * 16;
471 const int kPayloadBytes = kSamples * 2;
472 while (frame_index < kNumFrames) {
473 // Insert one packet each time, except every 10th time where we insert two
474 // packets at once. This will create a negative clock-drift of approx. 10%.
475 int num_packets = (frame_index % 10 == 0 ? 2 : 1);
476 for (int n = 0; n < num_packets; ++n) {
477 uint8_t payload[kPayloadBytes] = {0};
478 WebRtcRTPHeader rtp_info;
479 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
480 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
481 ++frame_index;
482 }
483
484 // Pull out data once.
485 int out_len;
486 int num_channels;
487 NetEqOutputType type;
488 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
489 &num_channels, &type));
490 ASSERT_EQ(kBlockSize16kHz, out_len);
491 }
492
493 NetEqNetworkStatistics network_stats;
494 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
495 EXPECT_EQ(-103196, network_stats.clockdrift_ppm);
496}
497
498TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimePositive) {
499 const int kNumFrames = 5000; // Needed for convergence.
500 int frame_index = 0;
501 const int kSamples = 10 * 16;
502 const int kPayloadBytes = kSamples * 2;
503 for (int i = 0; i < kNumFrames; ++i) {
504 // Insert one packet each time, except every 10th time where we don't insert
505 // any packet. This will create a positive clock-drift of approx. 11%.
506 int num_packets = (i % 10 == 9 ? 0 : 1);
507 for (int n = 0; n < num_packets; ++n) {
508 uint8_t payload[kPayloadBytes] = {0};
509 WebRtcRTPHeader rtp_info;
510 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
511 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
512 ++frame_index;
513 }
514
515 // Pull out data once.
516 int out_len;
517 int num_channels;
518 NetEqOutputType type;
519 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
520 &num_channels, &type));
521 ASSERT_EQ(kBlockSize16kHz, out_len);
522 }
523
524 NetEqNetworkStatistics network_stats;
525 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
526 EXPECT_EQ(110946, network_stats.clockdrift_ppm);
527}
528
529TEST_F(NetEqDecodingTest, LongCngWithClockDrift) {
530 uint16_t seq_no = 0;
531 uint32_t timestamp = 0;
532 const int kFrameSizeMs = 30;
533 const int kSamples = kFrameSizeMs * 16;
534 const int kPayloadBytes = kSamples * 2;
535 // Apply a clock drift of -25 ms / s (sender faster than receiver).
536 const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
537 double next_input_time_ms = 0.0;
538 double t_ms;
539 NetEqOutputType type;
540
541 // Insert speech for 5 seconds.
542 const int kSpeechDurationMs = 5000;
543 for (t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
544 // Each turn in this for loop is 10 ms.
545 while (next_input_time_ms <= t_ms) {
546 // Insert one 30 ms speech frame.
547 uint8_t payload[kPayloadBytes] = {0};
548 WebRtcRTPHeader rtp_info;
549 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
550 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
551 ++seq_no;
552 timestamp += kSamples;
553 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
554 }
555 // Pull out data once.
556 int out_len;
557 int num_channels;
558 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
559 &num_channels, &type));
560 ASSERT_EQ(kBlockSize16kHz, out_len);
561 }
562
563 EXPECT_EQ(kOutputNormal, type);
564 int32_t delay_before = timestamp - neteq_->PlayoutTimestamp();
565
566 // Insert CNG for 1 minute (= 60000 ms).
567 const int kCngPeriodMs = 100;
568 const int kCngPeriodSamples = kCngPeriodMs * 16; // Period in 16 kHz samples.
569 const int kCngDurationMs = 60000;
570 for (; t_ms < kSpeechDurationMs + kCngDurationMs; t_ms += 10) {
571 // Each turn in this for loop is 10 ms.
572 while (next_input_time_ms <= t_ms) {
573 // Insert one CNG frame each 100 ms.
574 uint8_t payload[kPayloadBytes];
575 int payload_len;
576 WebRtcRTPHeader rtp_info;
577 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
578 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
579 ++seq_no;
580 timestamp += kCngPeriodSamples;
581 next_input_time_ms += static_cast<double>(kCngPeriodMs) * kDriftFactor;
582 }
583 // Pull out data once.
584 int out_len;
585 int num_channels;
586 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
587 &num_channels, &type));
588 ASSERT_EQ(kBlockSize16kHz, out_len);
589 }
590
591 EXPECT_EQ(kOutputCNG, type);
592
593 // Insert speech again until output type is speech.
594 while (type != kOutputNormal) {
595 // Each turn in this for loop is 10 ms.
596 while (next_input_time_ms <= t_ms) {
597 // Insert one 30 ms speech frame.
598 uint8_t payload[kPayloadBytes] = {0};
599 WebRtcRTPHeader rtp_info;
600 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
601 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
602 ++seq_no;
603 timestamp += kSamples;
604 next_input_time_ms += static_cast<double>(kFrameSizeMs) * 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 // Increase clock.
613 t_ms += 10;
614 }
615
616 int32_t delay_after = timestamp - neteq_->PlayoutTimestamp();
617 // Compare delay before and after, and make sure it differs less than 20 ms.
618 EXPECT_LE(delay_after, delay_before + 20 * 16);
619 EXPECT_GE(delay_after, delay_before - 20 * 16);
620}
621
622TEST_F(NetEqDecodingTest, UnknownPayloadType) {
623 const int kPayloadBytes = 100;
624 uint8_t payload[kPayloadBytes] = {0};
625 WebRtcRTPHeader rtp_info;
626 PopulateRtpInfo(0, 0, &rtp_info);
627 rtp_info.header.payloadType = 1; // Not registered as a decoder.
628 EXPECT_EQ(NetEq::kFail,
629 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
630 EXPECT_EQ(NetEq::kUnknownRtpPayloadType, neteq_->LastError());
631}
632
633TEST_F(NetEqDecodingTest, DecoderError) {
634 const int kPayloadBytes = 100;
635 uint8_t payload[kPayloadBytes] = {0};
636 WebRtcRTPHeader rtp_info;
637 PopulateRtpInfo(0, 0, &rtp_info);
638 rtp_info.header.payloadType = 103; // iSAC, but the payload is invalid.
639 EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
640 NetEqOutputType type;
641 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
642 // to GetAudio.
643 for (int i = 0; i < kMaxBlockSize; ++i) {
644 out_data_[i] = 1;
645 }
646 int num_channels;
647 int samples_per_channel;
648 EXPECT_EQ(NetEq::kFail,
649 neteq_->GetAudio(kMaxBlockSize, out_data_,
650 &samples_per_channel, &num_channels, &type));
651 // Verify that there is a decoder error to check.
652 EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
653 // Code 6730 is an iSAC error code.
654 EXPECT_EQ(6730, neteq_->LastDecoderError());
655 // Verify that the first 160 samples are set to 0, and that the remaining
656 // samples are left unmodified.
657 static const int kExpectedOutputLength = 160; // 10 ms at 16 kHz sample rate.
658 for (int i = 0; i < kExpectedOutputLength; ++i) {
659 std::ostringstream ss;
660 ss << "i = " << i;
661 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
662 EXPECT_EQ(0, out_data_[i]);
663 }
664 for (int i = kExpectedOutputLength; i < kMaxBlockSize; ++i) {
665 std::ostringstream ss;
666 ss << "i = " << i;
667 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
668 EXPECT_EQ(1, out_data_[i]);
669 }
670}
671
672TEST_F(NetEqDecodingTest, GetAudioBeforeInsertPacket) {
673 NetEqOutputType type;
674 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
675 // to GetAudio.
676 for (int i = 0; i < kMaxBlockSize; ++i) {
677 out_data_[i] = 1;
678 }
679 int num_channels;
680 int samples_per_channel;
681 EXPECT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_,
682 &samples_per_channel,
683 &num_channels, &type));
684 // Verify that the first block of samples is set to 0.
685 static const int kExpectedOutputLength =
686 kInitSampleRateHz / 100; // 10 ms at initial sample rate.
687 for (int i = 0; i < kExpectedOutputLength; ++i) {
688 std::ostringstream ss;
689 ss << "i = " << i;
690 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
691 EXPECT_EQ(0, out_data_[i]);
692 }
693}
694} // namespace