blob: c6120ceaededc06f3ae581aec04222313602cb80 [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
turaj@webrtc.orgff43c852013-09-25 00:07:27 +000020#include <cmath>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000021#include <string>
22#include <vector>
23
24#include "gtest/gtest.h"
25#include "webrtc/modules/audio_coding/neteq4/test/NETEQTEST_RTPpacket.h"
turaj@webrtc.orgff43c852013-09-25 00:07:27 +000026#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000027#include "webrtc/test/testsupport/fileutils.h"
henrike@webrtc.orga950300b2013-07-08 18:53:54 +000028#include "webrtc/test/testsupport/gtest_disable.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000029#include "webrtc/typedefs.h"
30
31namespace webrtc {
32
33class RefFiles {
34 public:
35 RefFiles(const std::string& input_file, const std::string& output_file);
36 ~RefFiles();
37 template<class T> void ProcessReference(const T& test_results);
38 template<typename T, size_t n> void ProcessReference(
39 const T (&test_results)[n],
40 size_t length);
41 template<typename T, size_t n> void WriteToFile(
42 const T (&test_results)[n],
43 size_t length);
44 template<typename T, size_t n> void ReadFromFileAndCompare(
45 const T (&test_results)[n],
46 size_t length);
47 void WriteToFile(const NetEqNetworkStatistics& stats);
48 void ReadFromFileAndCompare(const NetEqNetworkStatistics& stats);
49 void WriteToFile(const RtcpStatistics& stats);
50 void ReadFromFileAndCompare(const RtcpStatistics& stats);
51
52 FILE* input_fp_;
53 FILE* output_fp_;
54};
55
56RefFiles::RefFiles(const std::string &input_file,
57 const std::string &output_file)
58 : input_fp_(NULL),
59 output_fp_(NULL) {
60 if (!input_file.empty()) {
61 input_fp_ = fopen(input_file.c_str(), "rb");
62 EXPECT_TRUE(input_fp_ != NULL);
63 }
64 if (!output_file.empty()) {
65 output_fp_ = fopen(output_file.c_str(), "wb");
66 EXPECT_TRUE(output_fp_ != NULL);
67 }
68}
69
70RefFiles::~RefFiles() {
71 if (input_fp_) {
72 EXPECT_EQ(EOF, fgetc(input_fp_)); // Make sure that we reached the end.
73 fclose(input_fp_);
74 }
75 if (output_fp_) fclose(output_fp_);
76}
77
78template<class T>
79void RefFiles::ProcessReference(const T& test_results) {
80 WriteToFile(test_results);
81 ReadFromFileAndCompare(test_results);
82}
83
84template<typename T, size_t n>
85void RefFiles::ProcessReference(const T (&test_results)[n], size_t length) {
86 WriteToFile(test_results, length);
87 ReadFromFileAndCompare(test_results, length);
88}
89
90template<typename T, size_t n>
91void RefFiles::WriteToFile(const T (&test_results)[n], size_t length) {
92 if (output_fp_) {
93 ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_));
94 }
95}
96
97template<typename T, size_t n>
98void RefFiles::ReadFromFileAndCompare(const T (&test_results)[n],
99 size_t length) {
100 if (input_fp_) {
101 // Read from ref file.
102 T* ref = new T[length];
103 ASSERT_EQ(length, fread(ref, sizeof(T), length, input_fp_));
104 // Compare
105 ASSERT_EQ(0, memcmp(&test_results, ref, sizeof(T) * length));
106 delete [] ref;
107 }
108}
109
110void RefFiles::WriteToFile(const NetEqNetworkStatistics& stats) {
111 if (output_fp_) {
112 ASSERT_EQ(1u, fwrite(&stats, sizeof(NetEqNetworkStatistics), 1,
113 output_fp_));
114 }
115}
116
117void RefFiles::ReadFromFileAndCompare(
118 const NetEqNetworkStatistics& stats) {
119 if (input_fp_) {
120 // Read from ref file.
121 size_t stat_size = sizeof(NetEqNetworkStatistics);
122 NetEqNetworkStatistics ref_stats;
123 ASSERT_EQ(1u, fread(&ref_stats, stat_size, 1, input_fp_));
124 // Compare
125 EXPECT_EQ(0, memcmp(&stats, &ref_stats, stat_size));
126 }
127}
128
129void RefFiles::WriteToFile(const RtcpStatistics& stats) {
130 if (output_fp_) {
131 ASSERT_EQ(1u, fwrite(&(stats.fraction_lost), sizeof(stats.fraction_lost), 1,
132 output_fp_));
133 ASSERT_EQ(1u, fwrite(&(stats.cumulative_lost),
134 sizeof(stats.cumulative_lost), 1, output_fp_));
135 ASSERT_EQ(1u, fwrite(&(stats.extended_max), sizeof(stats.extended_max), 1,
136 output_fp_));
137 ASSERT_EQ(1u, fwrite(&(stats.jitter), sizeof(stats.jitter), 1,
138 output_fp_));
139 }
140}
141
142void RefFiles::ReadFromFileAndCompare(
143 const RtcpStatistics& stats) {
144 if (input_fp_) {
145 // Read from ref file.
146 RtcpStatistics ref_stats;
147 ASSERT_EQ(1u, fread(&(ref_stats.fraction_lost),
148 sizeof(ref_stats.fraction_lost), 1, input_fp_));
149 ASSERT_EQ(1u, fread(&(ref_stats.cumulative_lost),
150 sizeof(ref_stats.cumulative_lost), 1, input_fp_));
151 ASSERT_EQ(1u, fread(&(ref_stats.extended_max),
152 sizeof(ref_stats.extended_max), 1, input_fp_));
153 ASSERT_EQ(1u, fread(&(ref_stats.jitter), sizeof(ref_stats.jitter), 1,
154 input_fp_));
155 // Compare
156 EXPECT_EQ(ref_stats.fraction_lost, stats.fraction_lost);
157 EXPECT_EQ(ref_stats.cumulative_lost, stats.cumulative_lost);
158 EXPECT_EQ(ref_stats.extended_max, stats.extended_max);
159 EXPECT_EQ(ref_stats.jitter, stats.jitter);
160 }
161}
162
163class NetEqDecodingTest : public ::testing::Test {
164 protected:
165 // NetEQ must be polled for data once every 10 ms. Thus, neither of the
166 // constants below can be changed.
167 static const int kTimeStepMs = 10;
168 static const int kBlockSize8kHz = kTimeStepMs * 8;
169 static const int kBlockSize16kHz = kTimeStepMs * 16;
170 static const int kBlockSize32kHz = kTimeStepMs * 32;
171 static const int kMaxBlockSize = kBlockSize32kHz;
172 static const int kInitSampleRateHz = 8000;
173
174 NetEqDecodingTest();
175 virtual void SetUp();
176 virtual void TearDown();
177 void SelectDecoders(NetEqDecoder* used_codec);
178 void LoadDecoders();
179 void OpenInputFile(const std::string &rtp_file);
180 void Process(NETEQTEST_RTPpacket* rtp_ptr, int* out_len);
181 void DecodeAndCompare(const std::string &rtp_file,
182 const std::string &ref_file);
183 void DecodeAndCheckStats(const std::string &rtp_file,
184 const std::string &stat_ref_file,
185 const std::string &rtcp_ref_file);
186 static void PopulateRtpInfo(int frame_index,
187 int timestamp,
188 WebRtcRTPHeader* rtp_info);
189 static void PopulateCng(int frame_index,
190 int timestamp,
191 WebRtcRTPHeader* rtp_info,
192 uint8_t* payload,
193 int* payload_len);
194
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000195 void CheckBgnOff(int sampling_rate, NetEqBackgroundNoiseMode bgn_mode);
196
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000197 NetEq* neteq_;
198 FILE* rtp_fp_;
199 unsigned int sim_clock_;
200 int16_t out_data_[kMaxBlockSize];
201 int output_sample_rate_;
202};
203
204// Allocating the static const so that it can be passed by reference.
205const int NetEqDecodingTest::kTimeStepMs;
206const int NetEqDecodingTest::kBlockSize8kHz;
207const int NetEqDecodingTest::kBlockSize16kHz;
208const int NetEqDecodingTest::kBlockSize32kHz;
209const int NetEqDecodingTest::kMaxBlockSize;
210const int NetEqDecodingTest::kInitSampleRateHz;
211
212NetEqDecodingTest::NetEqDecodingTest()
213 : neteq_(NULL),
214 rtp_fp_(NULL),
215 sim_clock_(0),
216 output_sample_rate_(kInitSampleRateHz) {
217 memset(out_data_, 0, sizeof(out_data_));
218}
219
220void NetEqDecodingTest::SetUp() {
221 neteq_ = NetEq::Create(kInitSampleRateHz);
222 ASSERT_TRUE(neteq_);
223 LoadDecoders();
224}
225
226void NetEqDecodingTest::TearDown() {
227 delete neteq_;
228 if (rtp_fp_)
229 fclose(rtp_fp_);
230}
231
232void NetEqDecodingTest::LoadDecoders() {
233 // Load PCMu.
234 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCMu, 0));
235 // Load PCMa.
236 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCMa, 8));
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000237#ifndef WEBRTC_ANDROID
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000238 // Load iLBC.
239 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderILBC, 102));
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000240#endif // WEBRTC_ANDROID
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000241 // Load iSAC.
242 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISAC, 103));
243 // Load iSAC SWB.
244 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACswb, 104));
henrik.lundin@webrtc.orgac59dba2013-01-31 09:55:24 +0000245 // Load iSAC FB.
246 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACfb, 105));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000247 // Load PCM16B nb.
248 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16B, 93));
249 // Load PCM16B wb.
250 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bwb, 94));
251 // Load PCM16B swb32.
252 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bswb32kHz, 95));
253 // Load CNG 8 kHz.
254 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGnb, 13));
255 // Load CNG 16 kHz.
256 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGwb, 98));
257}
258
259void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
260 rtp_fp_ = fopen(rtp_file.c_str(), "rb");
261 ASSERT_TRUE(rtp_fp_ != NULL);
262 ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp_));
263}
264
265void NetEqDecodingTest::Process(NETEQTEST_RTPpacket* rtp, int* out_len) {
266 // Check if time to receive.
267 while ((sim_clock_ >= rtp->time()) &&
268 (rtp->dataLen() >= 0)) {
269 if (rtp->dataLen() > 0) {
270 WebRtcRTPHeader rtpInfo;
271 rtp->parseHeader(&rtpInfo);
272 ASSERT_EQ(0, neteq_->InsertPacket(
273 rtpInfo,
274 rtp->payload(),
275 rtp->payloadLen(),
276 rtp->time() * (output_sample_rate_ / 1000)));
277 }
278 // Get next packet.
279 ASSERT_NE(-1, rtp->readFromFile(rtp_fp_));
280 }
281
henrik.lundin@webrtc.orge1d468c2013-01-30 07:37:20 +0000282 // Get audio from NetEq.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000283 NetEqOutputType type;
284 int num_channels;
285 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, out_len,
286 &num_channels, &type));
287 ASSERT_TRUE((*out_len == kBlockSize8kHz) ||
288 (*out_len == kBlockSize16kHz) ||
289 (*out_len == kBlockSize32kHz));
290 output_sample_rate_ = *out_len / 10 * 1000;
291
292 // Increase time.
293 sim_clock_ += kTimeStepMs;
294}
295
296void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
297 const std::string &ref_file) {
298 OpenInputFile(rtp_file);
299
300 std::string ref_out_file = "";
301 if (ref_file.empty()) {
302 ref_out_file = webrtc::test::OutputPath() + "neteq_out.pcm";
303 }
304 RefFiles ref_files(ref_file, ref_out_file);
305
306 NETEQTEST_RTPpacket rtp;
307 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
308 int i = 0;
309 while (rtp.dataLen() >= 0) {
310 std::ostringstream ss;
311 ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
312 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
313 int out_len;
314 ASSERT_NO_FATAL_FAILURE(Process(&rtp, &out_len));
315 ASSERT_NO_FATAL_FAILURE(ref_files.ProcessReference(out_data_, out_len));
316 }
317}
318
319void NetEqDecodingTest::DecodeAndCheckStats(const std::string &rtp_file,
320 const std::string &stat_ref_file,
321 const std::string &rtcp_ref_file) {
322 OpenInputFile(rtp_file);
323 std::string stat_out_file = "";
324 if (stat_ref_file.empty()) {
325 stat_out_file = webrtc::test::OutputPath() +
326 "neteq_network_stats.dat";
327 }
328 RefFiles network_stat_files(stat_ref_file, stat_out_file);
329
330 std::string rtcp_out_file = "";
331 if (rtcp_ref_file.empty()) {
332 rtcp_out_file = webrtc::test::OutputPath() +
333 "neteq_rtcp_stats.dat";
334 }
335 RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);
336
337 NETEQTEST_RTPpacket rtp;
338 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
339 while (rtp.dataLen() >= 0) {
340 int out_len;
341 Process(&rtp, &out_len);
342
343 // Query the network statistics API once per second
344 if (sim_clock_ % 1000 == 0) {
345 // Process NetworkStatistics.
346 NetEqNetworkStatistics network_stats;
347 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
348 network_stat_files.ProcessReference(network_stats);
349
350 // Process RTCPstat.
351 RtcpStatistics rtcp_stats;
352 neteq_->GetRtcpStatistics(&rtcp_stats);
353 rtcp_stat_files.ProcessReference(rtcp_stats);
354 }
355 }
356}
357
358void NetEqDecodingTest::PopulateRtpInfo(int frame_index,
359 int timestamp,
360 WebRtcRTPHeader* rtp_info) {
361 rtp_info->header.sequenceNumber = frame_index;
362 rtp_info->header.timestamp = timestamp;
363 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
364 rtp_info->header.payloadType = 94; // PCM16b WB codec.
365 rtp_info->header.markerBit = 0;
366}
367
368void NetEqDecodingTest::PopulateCng(int frame_index,
369 int timestamp,
370 WebRtcRTPHeader* rtp_info,
371 uint8_t* payload,
372 int* payload_len) {
373 rtp_info->header.sequenceNumber = frame_index;
374 rtp_info->header.timestamp = timestamp;
375 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
376 rtp_info->header.payloadType = 98; // WB CNG.
377 rtp_info->header.markerBit = 0;
378 payload[0] = 64; // Noise level -64 dBov, quite arbitrarily chosen.
379 *payload_len = 1; // Only noise level, no spectral parameters.
380}
381
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000382void NetEqDecodingTest::CheckBgnOff(int sampling_rate_hz,
383 NetEqBackgroundNoiseMode bgn_mode) {
384 int expected_samples_per_channel = 0;
385 uint8_t payload_type = 0xFF; // Invalid.
386 if (sampling_rate_hz == 8000) {
387 expected_samples_per_channel = kBlockSize8kHz;
388 payload_type = 93; // PCM 16, 8 kHz.
389 } else if (sampling_rate_hz == 16000) {
390 expected_samples_per_channel = kBlockSize16kHz;
391 payload_type = 94; // PCM 16, 16 kHZ.
392 } else if (sampling_rate_hz == 32000) {
393 expected_samples_per_channel = kBlockSize32kHz;
394 payload_type = 95; // PCM 16, 32 kHz.
395 } else {
396 ASSERT_TRUE(false); // Unsupported test case.
397 }
398
399 NetEqOutputType type;
400 int16_t output[kBlockSize32kHz]; // Maximum size is chosen.
401 int16_t input[kBlockSize32kHz]; // Maximum size is chosen.
402
403 // Payload of 10 ms of PCM16 32 kHz.
404 uint8_t payload[kBlockSize32kHz * sizeof(int16_t)];
405
406 // Random payload.
407 for (int n = 0; n < expected_samples_per_channel; ++n) {
408 input[n] = (rand() & ((1 << 10) - 1)) - ((1 << 5) - 1);
409 }
410 int enc_len_bytes = WebRtcPcm16b_EncodeW16(
411 input, expected_samples_per_channel, reinterpret_cast<int16_t*>(payload));
412 ASSERT_EQ(enc_len_bytes, expected_samples_per_channel * 2);
413
414 WebRtcRTPHeader rtp_info;
415 PopulateRtpInfo(0, 0, &rtp_info);
416 rtp_info.header.payloadType = payload_type;
417
418 int number_channels = 0;
419 int samples_per_channel = 0;
420
421 uint32_t receive_timestamp = 0;
422 for (int n = 0; n < 10; ++n) { // Insert few packets and get audio.
423 number_channels = 0;
424 samples_per_channel = 0;
425 ASSERT_EQ(0, neteq_->InsertPacket(
426 rtp_info, payload, enc_len_bytes, receive_timestamp));
427 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
428 &number_channels, &type));
429 ASSERT_EQ(1, number_channels);
430 ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
431 ASSERT_EQ(kOutputNormal, type);
432
433 // Next packet.
434 rtp_info.header.timestamp += expected_samples_per_channel;
435 rtp_info.header.sequenceNumber++;
436 receive_timestamp += expected_samples_per_channel;
437 }
438
439 number_channels = 0;
440 samples_per_channel = 0;
441
442 // Get audio without inserting packets, expecting PLC and PLC-to-CNG. Pull one
443 // frame without checking speech-type. This is the first frame pulled without
444 // inserting any packet, and might not be labeled as PCL.
445 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
446 &number_channels, &type));
447 ASSERT_EQ(1, number_channels);
448 ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
449
450 // To be able to test the fading of background noise we need at lease to pull
451 // 610 frames.
452 const int kFadingThreshold = 610;
453
454 // Test several CNG-to-PLC packet for the expected behavior. The number 20 is
455 // arbitrary, but sufficiently large to test enough number of frames.
456 const int kNumPlcToCngTestFrames = 20;
457 bool plc_to_cng = false;
458 for (int n = 0; n < kFadingThreshold + kNumPlcToCngTestFrames; ++n) {
459 number_channels = 0;
460 samples_per_channel = 0;
461 memset(output, 1, sizeof(output)); // Set to non-zero.
462 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
463 &number_channels, &type));
464 ASSERT_EQ(1, number_channels);
465 ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
466 if (type == kOutputPLCtoCNG) {
467 plc_to_cng = true;
468 double sum_squared = 0;
469 for (int k = 0; k < number_channels * samples_per_channel; ++k)
470 sum_squared += output[k] * output[k];
471 if (bgn_mode == kBgnOn) {
472 EXPECT_NE(0, sum_squared);
473 } else if (bgn_mode == kBgnOff || n > kFadingThreshold) {
474 EXPECT_EQ(0, sum_squared);
475 }
476 } else {
477 EXPECT_EQ(kOutputPLC, type);
478 }
479 }
480 EXPECT_TRUE(plc_to_cng); // Just to be sure that PLC-to-CNG has occurred.
481}
482
kjellander@webrtc.org6eba2772013-06-04 05:46:37 +0000483#if defined(_WIN32) && defined(WEBRTC_ARCH_64_BITS)
484// Disabled for Windows 64-bit until webrtc:1458 is fixed.
485#define MAYBE_TestBitExactness DISABLED_TestBitExactness
486#else
487#define MAYBE_TestBitExactness TestBitExactness
488#endif
489
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000490TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(MAYBE_TestBitExactness)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000491 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000492 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000493#if defined(_MSC_VER) && (_MSC_VER >= 1700)
494 // For Visual Studio 2012 and later, we will have to use the generic reference
495 // file, rather than the windows-specific one.
496 const std::string kInputRefFile = webrtc::test::ProjectRootPath() +
497 "resources/audio_coding/neteq_universal_ref.pcm";
498#else
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000499 const std::string kInputRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000500 webrtc::test::ResourcePath("audio_coding/neteq_universal_ref", "pcm");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000501#endif
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000502 DecodeAndCompare(kInputRtpFile, kInputRefFile);
503}
504
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000505TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(TestNetworkStatistics)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000506 const std::string kInputRtpFile = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000507 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000508#if defined(_MSC_VER) && (_MSC_VER >= 1700)
509 // For Visual Studio 2012 and later, we will have to use the generic reference
510 // file, rather than the windows-specific one.
511 const std::string kNetworkStatRefFile = webrtc::test::ProjectRootPath() +
512 "resources/audio_coding/neteq_network_stats.dat";
513#else
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000514 const std::string kNetworkStatRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000515 webrtc::test::ResourcePath("audio_coding/neteq_network_stats", "dat");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000516#endif
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000517 const std::string kRtcpStatRefFile =
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000518 webrtc::test::ResourcePath("audio_coding/neteq_rtcp_stats", "dat");
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000519 DecodeAndCheckStats(kInputRtpFile, kNetworkStatRefFile, kRtcpStatRefFile);
520}
521
522// TODO(hlundin): Re-enable test once the statistics interface is up and again.
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000523TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(TestFrameWaitingTimeStatistics)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000524 // Use fax mode to avoid time-scaling. This is to simplify the testing of
525 // packet waiting times in the packet buffer.
526 neteq_->SetPlayoutMode(kPlayoutFax);
527 ASSERT_EQ(kPlayoutFax, neteq_->PlayoutMode());
528 // Insert 30 dummy packets at once. Each packet contains 10 ms 16 kHz audio.
529 size_t num_frames = 30;
530 const int kSamples = 10 * 16;
531 const int kPayloadBytes = kSamples * 2;
532 for (size_t i = 0; i < num_frames; ++i) {
533 uint16_t payload[kSamples] = {0};
534 WebRtcRTPHeader rtp_info;
535 rtp_info.header.sequenceNumber = i;
536 rtp_info.header.timestamp = i * kSamples;
537 rtp_info.header.ssrc = 0x1234; // Just an arbitrary SSRC.
538 rtp_info.header.payloadType = 94; // PCM16b WB codec.
539 rtp_info.header.markerBit = 0;
540 ASSERT_EQ(0, neteq_->InsertPacket(
541 rtp_info,
542 reinterpret_cast<uint8_t*>(payload),
543 kPayloadBytes, 0));
544 }
545 // Pull out all data.
546 for (size_t i = 0; i < num_frames; ++i) {
547 int out_len;
548 int num_channels;
549 NetEqOutputType type;
550 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
551 &num_channels, &type));
552 ASSERT_EQ(kBlockSize16kHz, out_len);
553 }
554
555 std::vector<int> waiting_times;
556 neteq_->WaitingTimes(&waiting_times);
557 int len = waiting_times.size();
558 EXPECT_EQ(num_frames, waiting_times.size());
559 // Since all frames are dumped into NetEQ at once, but pulled out with 10 ms
560 // spacing (per definition), we expect the delay to increase with 10 ms for
561 // each packet.
562 for (size_t i = 0; i < waiting_times.size(); ++i) {
563 EXPECT_EQ(static_cast<int>(i + 1) * 10, waiting_times[i]);
564 }
565
566 // Check statistics again and make sure it's been reset.
567 neteq_->WaitingTimes(&waiting_times);
568 len = waiting_times.size();
569 EXPECT_EQ(0, len);
570
571 // Process > 100 frames, and make sure that that we get statistics
572 // only for 100 frames. Note the new SSRC, causing NetEQ to reset.
573 num_frames = 110;
574 for (size_t i = 0; i < num_frames; ++i) {
575 uint16_t payload[kSamples] = {0};
576 WebRtcRTPHeader rtp_info;
577 rtp_info.header.sequenceNumber = i;
578 rtp_info.header.timestamp = i * kSamples;
579 rtp_info.header.ssrc = 0x1235; // Just an arbitrary SSRC.
580 rtp_info.header.payloadType = 94; // PCM16b WB codec.
581 rtp_info.header.markerBit = 0;
582 ASSERT_EQ(0, neteq_->InsertPacket(
583 rtp_info,
584 reinterpret_cast<uint8_t*>(payload),
585 kPayloadBytes, 0));
586 int out_len;
587 int num_channels;
588 NetEqOutputType type;
589 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
590 &num_channels, &type));
591 ASSERT_EQ(kBlockSize16kHz, out_len);
592 }
593
594 neteq_->WaitingTimes(&waiting_times);
595 EXPECT_EQ(100u, waiting_times.size());
596}
597
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000598TEST_F(NetEqDecodingTest,
599 DISABLED_ON_ANDROID(TestAverageInterArrivalTimeNegative)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000600 const int kNumFrames = 3000; // Needed for convergence.
601 int frame_index = 0;
602 const int kSamples = 10 * 16;
603 const int kPayloadBytes = kSamples * 2;
604 while (frame_index < kNumFrames) {
605 // Insert one packet each time, except every 10th time where we insert two
606 // packets at once. This will create a negative clock-drift of approx. 10%.
607 int num_packets = (frame_index % 10 == 0 ? 2 : 1);
608 for (int n = 0; n < num_packets; ++n) {
609 uint8_t payload[kPayloadBytes] = {0};
610 WebRtcRTPHeader rtp_info;
611 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
612 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
613 ++frame_index;
614 }
615
616 // Pull out data once.
617 int out_len;
618 int num_channels;
619 NetEqOutputType type;
620 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
621 &num_channels, &type));
622 ASSERT_EQ(kBlockSize16kHz, out_len);
623 }
624
625 NetEqNetworkStatistics network_stats;
626 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
627 EXPECT_EQ(-103196, network_stats.clockdrift_ppm);
628}
629
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000630TEST_F(NetEqDecodingTest,
631 DISABLED_ON_ANDROID(TestAverageInterArrivalTimePositive)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000632 const int kNumFrames = 5000; // Needed for convergence.
633 int frame_index = 0;
634 const int kSamples = 10 * 16;
635 const int kPayloadBytes = kSamples * 2;
636 for (int i = 0; i < kNumFrames; ++i) {
637 // Insert one packet each time, except every 10th time where we don't insert
638 // any packet. This will create a positive clock-drift of approx. 11%.
639 int num_packets = (i % 10 == 9 ? 0 : 1);
640 for (int n = 0; n < num_packets; ++n) {
641 uint8_t payload[kPayloadBytes] = {0};
642 WebRtcRTPHeader rtp_info;
643 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
644 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
645 ++frame_index;
646 }
647
648 // Pull out data once.
649 int out_len;
650 int num_channels;
651 NetEqOutputType type;
652 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
653 &num_channels, &type));
654 ASSERT_EQ(kBlockSize16kHz, out_len);
655 }
656
657 NetEqNetworkStatistics network_stats;
658 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
659 EXPECT_EQ(110946, network_stats.clockdrift_ppm);
660}
661
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000662TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(LongCngWithClockDrift)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000663 uint16_t seq_no = 0;
664 uint32_t timestamp = 0;
665 const int kFrameSizeMs = 30;
666 const int kSamples = kFrameSizeMs * 16;
667 const int kPayloadBytes = kSamples * 2;
668 // Apply a clock drift of -25 ms / s (sender faster than receiver).
669 const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
670 double next_input_time_ms = 0.0;
671 double t_ms;
672 NetEqOutputType type;
673
674 // Insert speech for 5 seconds.
675 const int kSpeechDurationMs = 5000;
676 for (t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
677 // Each turn in this for loop is 10 ms.
678 while (next_input_time_ms <= t_ms) {
679 // Insert one 30 ms speech frame.
680 uint8_t payload[kPayloadBytes] = {0};
681 WebRtcRTPHeader rtp_info;
682 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
683 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
684 ++seq_no;
685 timestamp += kSamples;
686 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
687 }
688 // Pull out data once.
689 int out_len;
690 int num_channels;
691 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
692 &num_channels, &type));
693 ASSERT_EQ(kBlockSize16kHz, out_len);
694 }
695
696 EXPECT_EQ(kOutputNormal, type);
697 int32_t delay_before = timestamp - neteq_->PlayoutTimestamp();
698
699 // Insert CNG for 1 minute (= 60000 ms).
700 const int kCngPeriodMs = 100;
701 const int kCngPeriodSamples = kCngPeriodMs * 16; // Period in 16 kHz samples.
702 const int kCngDurationMs = 60000;
703 for (; t_ms < kSpeechDurationMs + kCngDurationMs; t_ms += 10) {
704 // Each turn in this for loop is 10 ms.
705 while (next_input_time_ms <= t_ms) {
706 // Insert one CNG frame each 100 ms.
707 uint8_t payload[kPayloadBytes];
708 int payload_len;
709 WebRtcRTPHeader rtp_info;
710 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
711 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
712 ++seq_no;
713 timestamp += kCngPeriodSamples;
714 next_input_time_ms += static_cast<double>(kCngPeriodMs) * kDriftFactor;
715 }
716 // Pull out data once.
717 int out_len;
718 int num_channels;
719 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
720 &num_channels, &type));
721 ASSERT_EQ(kBlockSize16kHz, out_len);
722 }
723
724 EXPECT_EQ(kOutputCNG, type);
725
726 // Insert speech again until output type is speech.
727 while (type != kOutputNormal) {
728 // Each turn in this for loop is 10 ms.
729 while (next_input_time_ms <= t_ms) {
730 // Insert one 30 ms speech frame.
731 uint8_t payload[kPayloadBytes] = {0};
732 WebRtcRTPHeader rtp_info;
733 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
734 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
735 ++seq_no;
736 timestamp += kSamples;
737 next_input_time_ms += static_cast<double>(kFrameSizeMs) * kDriftFactor;
738 }
739 // Pull out data once.
740 int out_len;
741 int num_channels;
742 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
743 &num_channels, &type));
744 ASSERT_EQ(kBlockSize16kHz, out_len);
745 // Increase clock.
746 t_ms += 10;
747 }
748
749 int32_t delay_after = timestamp - neteq_->PlayoutTimestamp();
750 // Compare delay before and after, and make sure it differs less than 20 ms.
751 EXPECT_LE(delay_after, delay_before + 20 * 16);
752 EXPECT_GE(delay_after, delay_before - 20 * 16);
753}
754
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000755TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(UnknownPayloadType)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000756 const int kPayloadBytes = 100;
757 uint8_t payload[kPayloadBytes] = {0};
758 WebRtcRTPHeader rtp_info;
759 PopulateRtpInfo(0, 0, &rtp_info);
760 rtp_info.header.payloadType = 1; // Not registered as a decoder.
761 EXPECT_EQ(NetEq::kFail,
762 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
763 EXPECT_EQ(NetEq::kUnknownRtpPayloadType, neteq_->LastError());
764}
765
minyue@webrtc.org7bb54362013-08-06 05:40:57 +0000766TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(OversizePacket)) {
767 // Payload size is greater than packet buffer size
768 const int kPayloadBytes = NetEq::kMaxBytesInBuffer + 1;
769 uint8_t payload[kPayloadBytes] = {0};
770 WebRtcRTPHeader rtp_info;
771 PopulateRtpInfo(0, 0, &rtp_info);
772 rtp_info.header.payloadType = 103; // iSAC, no packet splitting.
773 EXPECT_EQ(NetEq::kFail,
774 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
775 EXPECT_EQ(NetEq::kOversizePacket, neteq_->LastError());
776}
777
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000778TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(DecoderError)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000779 const int kPayloadBytes = 100;
780 uint8_t payload[kPayloadBytes] = {0};
781 WebRtcRTPHeader rtp_info;
782 PopulateRtpInfo(0, 0, &rtp_info);
783 rtp_info.header.payloadType = 103; // iSAC, but the payload is invalid.
784 EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
785 NetEqOutputType type;
786 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
787 // to GetAudio.
788 for (int i = 0; i < kMaxBlockSize; ++i) {
789 out_data_[i] = 1;
790 }
791 int num_channels;
792 int samples_per_channel;
793 EXPECT_EQ(NetEq::kFail,
794 neteq_->GetAudio(kMaxBlockSize, out_data_,
795 &samples_per_channel, &num_channels, &type));
796 // Verify that there is a decoder error to check.
797 EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
798 // Code 6730 is an iSAC error code.
799 EXPECT_EQ(6730, neteq_->LastDecoderError());
800 // Verify that the first 160 samples are set to 0, and that the remaining
801 // samples are left unmodified.
802 static const int kExpectedOutputLength = 160; // 10 ms at 16 kHz sample rate.
803 for (int i = 0; i < kExpectedOutputLength; ++i) {
804 std::ostringstream ss;
805 ss << "i = " << i;
806 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
807 EXPECT_EQ(0, out_data_[i]);
808 }
809 for (int i = kExpectedOutputLength; i < kMaxBlockSize; ++i) {
810 std::ostringstream ss;
811 ss << "i = " << i;
812 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
813 EXPECT_EQ(1, out_data_[i]);
814 }
815}
816
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000817TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(GetAudioBeforeInsertPacket)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000818 NetEqOutputType type;
819 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
820 // to GetAudio.
821 for (int i = 0; i < kMaxBlockSize; ++i) {
822 out_data_[i] = 1;
823 }
824 int num_channels;
825 int samples_per_channel;
826 EXPECT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_,
827 &samples_per_channel,
828 &num_channels, &type));
829 // Verify that the first block of samples is set to 0.
830 static const int kExpectedOutputLength =
831 kInitSampleRateHz / 100; // 10 ms at initial sample rate.
832 for (int i = 0; i < kExpectedOutputLength; ++i) {
833 std::ostringstream ss;
834 ss << "i = " << i;
835 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
836 EXPECT_EQ(0, out_data_[i]);
837 }
838}
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000839
840TEST_F(NetEqDecodingTest, BackgroundNoise) {
841 neteq_->SetBackgroundNoiseMode(kBgnOn);
842 CheckBgnOff(8000, kBgnOn);
843 CheckBgnOff(16000, kBgnOn);
844 CheckBgnOff(32000, kBgnOn);
845 EXPECT_EQ(kBgnOn, neteq_->BackgroundNoiseMode());
846
847 neteq_->SetBackgroundNoiseMode(kBgnOff);
848 CheckBgnOff(8000, kBgnOff);
849 CheckBgnOff(16000, kBgnOff);
850 CheckBgnOff(32000, kBgnOff);
851 EXPECT_EQ(kBgnOff, neteq_->BackgroundNoiseMode());
852
853 neteq_->SetBackgroundNoiseMode(kBgnFade);
854 CheckBgnOff(8000, kBgnFade);
855 CheckBgnOff(16000, kBgnFade);
856 CheckBgnOff(32000, kBgnFade);
857 EXPECT_EQ(kBgnFade, neteq_->BackgroundNoiseMode());
858}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000859} // namespace