blob: c1a7e16526b007d67c65bb2e09aa19a144c6f29d [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
henrik.lundin@webrtc.org1b9df052014-05-28 07:33:39 +000015#include "webrtc/modules/audio_coding/neteq4/interface/neteq.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
pbos@webrtc.org3ecc1622014-03-07 15:23:34 +000017#include <math.h>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000018#include <stdlib.h>
19#include <string.h> // memset
20
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +000021#include <algorithm>
turaj@webrtc.org78b41a02013-11-22 20:27:07 +000022#include <set>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000023#include <string>
24#include <vector>
25
turaj@webrtc.orga6101d72013-10-01 22:01:09 +000026#include "gflags/gflags.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000027#include "gtest/gtest.h"
henrik.lundin@webrtc.org1b9df052014-05-28 07:33:39 +000028#include "webrtc/modules/audio_coding/neteq4/test/NETEQTEST_RTPpacket.h"
turaj@webrtc.orgff43c852013-09-25 00:07:27 +000029#include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000030#include "webrtc/test/testsupport/fileutils.h"
henrike@webrtc.orga950300b2013-07-08 18:53:54 +000031#include "webrtc/test/testsupport/gtest_disable.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000032#include "webrtc/typedefs.h"
33
turaj@webrtc.orga6101d72013-10-01 22:01:09 +000034DEFINE_bool(gen_ref, false, "Generate reference files.");
35
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000036namespace webrtc {
37
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +000038static bool IsAllZero(const int16_t* buf, int buf_length) {
39 bool all_zero = true;
40 for (int n = 0; n < buf_length && all_zero; ++n)
41 all_zero = buf[n] == 0;
42 return all_zero;
43}
44
45static bool IsAllNonZero(const int16_t* buf, int buf_length) {
46 bool all_non_zero = true;
47 for (int n = 0; n < buf_length && all_non_zero; ++n)
48 all_non_zero = buf[n] != 0;
49 return all_non_zero;
50}
51
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000052class RefFiles {
53 public:
54 RefFiles(const std::string& input_file, const std::string& output_file);
55 ~RefFiles();
56 template<class T> void ProcessReference(const T& test_results);
57 template<typename T, size_t n> void ProcessReference(
58 const T (&test_results)[n],
59 size_t length);
60 template<typename T, size_t n> void WriteToFile(
61 const T (&test_results)[n],
62 size_t length);
63 template<typename T, size_t n> void ReadFromFileAndCompare(
64 const T (&test_results)[n],
65 size_t length);
66 void WriteToFile(const NetEqNetworkStatistics& stats);
67 void ReadFromFileAndCompare(const NetEqNetworkStatistics& stats);
68 void WriteToFile(const RtcpStatistics& stats);
69 void ReadFromFileAndCompare(const RtcpStatistics& stats);
70
71 FILE* input_fp_;
72 FILE* output_fp_;
73};
74
75RefFiles::RefFiles(const std::string &input_file,
76 const std::string &output_file)
77 : input_fp_(NULL),
78 output_fp_(NULL) {
79 if (!input_file.empty()) {
80 input_fp_ = fopen(input_file.c_str(), "rb");
81 EXPECT_TRUE(input_fp_ != NULL);
82 }
83 if (!output_file.empty()) {
84 output_fp_ = fopen(output_file.c_str(), "wb");
85 EXPECT_TRUE(output_fp_ != NULL);
86 }
87}
88
89RefFiles::~RefFiles() {
90 if (input_fp_) {
91 EXPECT_EQ(EOF, fgetc(input_fp_)); // Make sure that we reached the end.
92 fclose(input_fp_);
93 }
94 if (output_fp_) fclose(output_fp_);
95}
96
97template<class T>
98void RefFiles::ProcessReference(const T& test_results) {
99 WriteToFile(test_results);
100 ReadFromFileAndCompare(test_results);
101}
102
103template<typename T, size_t n>
104void RefFiles::ProcessReference(const T (&test_results)[n], size_t length) {
105 WriteToFile(test_results, length);
106 ReadFromFileAndCompare(test_results, length);
107}
108
109template<typename T, size_t n>
110void RefFiles::WriteToFile(const T (&test_results)[n], size_t length) {
111 if (output_fp_) {
112 ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_));
113 }
114}
115
116template<typename T, size_t n>
117void RefFiles::ReadFromFileAndCompare(const T (&test_results)[n],
118 size_t length) {
119 if (input_fp_) {
120 // Read from ref file.
121 T* ref = new T[length];
122 ASSERT_EQ(length, fread(ref, sizeof(T), length, input_fp_));
123 // Compare
124 ASSERT_EQ(0, memcmp(&test_results, ref, sizeof(T) * length));
125 delete [] ref;
126 }
127}
128
129void RefFiles::WriteToFile(const NetEqNetworkStatistics& stats) {
130 if (output_fp_) {
131 ASSERT_EQ(1u, fwrite(&stats, sizeof(NetEqNetworkStatistics), 1,
132 output_fp_));
133 }
134}
135
136void RefFiles::ReadFromFileAndCompare(
137 const NetEqNetworkStatistics& stats) {
138 if (input_fp_) {
139 // Read from ref file.
140 size_t stat_size = sizeof(NetEqNetworkStatistics);
141 NetEqNetworkStatistics ref_stats;
142 ASSERT_EQ(1u, fread(&ref_stats, stat_size, 1, input_fp_));
143 // Compare
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000144 ASSERT_EQ(0, memcmp(&stats, &ref_stats, stat_size));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000145 }
146}
147
148void RefFiles::WriteToFile(const RtcpStatistics& stats) {
149 if (output_fp_) {
150 ASSERT_EQ(1u, fwrite(&(stats.fraction_lost), sizeof(stats.fraction_lost), 1,
151 output_fp_));
152 ASSERT_EQ(1u, fwrite(&(stats.cumulative_lost),
153 sizeof(stats.cumulative_lost), 1, output_fp_));
sprang@webrtc.orgfe5d36b2013-10-28 09:21:07 +0000154 ASSERT_EQ(1u, fwrite(&(stats.extended_max_sequence_number),
155 sizeof(stats.extended_max_sequence_number), 1,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000156 output_fp_));
157 ASSERT_EQ(1u, fwrite(&(stats.jitter), sizeof(stats.jitter), 1,
158 output_fp_));
159 }
160}
161
162void RefFiles::ReadFromFileAndCompare(
163 const RtcpStatistics& stats) {
164 if (input_fp_) {
165 // Read from ref file.
166 RtcpStatistics ref_stats;
167 ASSERT_EQ(1u, fread(&(ref_stats.fraction_lost),
168 sizeof(ref_stats.fraction_lost), 1, input_fp_));
169 ASSERT_EQ(1u, fread(&(ref_stats.cumulative_lost),
170 sizeof(ref_stats.cumulative_lost), 1, input_fp_));
sprang@webrtc.orgfe5d36b2013-10-28 09:21:07 +0000171 ASSERT_EQ(1u, fread(&(ref_stats.extended_max_sequence_number),
172 sizeof(ref_stats.extended_max_sequence_number), 1,
173 input_fp_));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000174 ASSERT_EQ(1u, fread(&(ref_stats.jitter), sizeof(ref_stats.jitter), 1,
175 input_fp_));
176 // Compare
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000177 ASSERT_EQ(ref_stats.fraction_lost, stats.fraction_lost);
178 ASSERT_EQ(ref_stats.cumulative_lost, stats.cumulative_lost);
179 ASSERT_EQ(ref_stats.extended_max_sequence_number,
sprang@webrtc.orgfe5d36b2013-10-28 09:21:07 +0000180 stats.extended_max_sequence_number);
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000181 ASSERT_EQ(ref_stats.jitter, stats.jitter);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000182 }
183}
184
185class NetEqDecodingTest : public ::testing::Test {
186 protected:
187 // NetEQ must be polled for data once every 10 ms. Thus, neither of the
188 // constants below can be changed.
189 static const int kTimeStepMs = 10;
190 static const int kBlockSize8kHz = kTimeStepMs * 8;
191 static const int kBlockSize16kHz = kTimeStepMs * 16;
192 static const int kBlockSize32kHz = kTimeStepMs * 32;
193 static const int kMaxBlockSize = kBlockSize32kHz;
194 static const int kInitSampleRateHz = 8000;
195
196 NetEqDecodingTest();
197 virtual void SetUp();
198 virtual void TearDown();
199 void SelectDecoders(NetEqDecoder* used_codec);
200 void LoadDecoders();
201 void OpenInputFile(const std::string &rtp_file);
202 void Process(NETEQTEST_RTPpacket* rtp_ptr, int* out_len);
203 void DecodeAndCompare(const std::string &rtp_file,
204 const std::string &ref_file);
205 void DecodeAndCheckStats(const std::string &rtp_file,
206 const std::string &stat_ref_file,
207 const std::string &rtcp_ref_file);
208 static void PopulateRtpInfo(int frame_index,
209 int timestamp,
210 WebRtcRTPHeader* rtp_info);
211 static void PopulateCng(int frame_index,
212 int timestamp,
213 WebRtcRTPHeader* rtp_info,
214 uint8_t* payload,
215 int* payload_len);
216
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000217 void CheckBgnOff(int sampling_rate, NetEqBackgroundNoiseMode bgn_mode);
218
turaj@webrtc.org78b41a02013-11-22 20:27:07 +0000219 void WrapTest(uint16_t start_seq_no, uint32_t start_timestamp,
220 const std::set<uint16_t>& drop_seq_numbers,
221 bool expect_seq_no_wrap, bool expect_timestamp_wrap);
222
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000223 void LongCngWithClockDrift(double drift_factor,
224 double network_freeze_ms,
225 bool pull_audio_during_freeze,
226 int delay_tolerance_ms,
227 int max_time_to_speech_ms);
228
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +0000229 void DuplicateCng();
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000230
wu@webrtc.org94454b72014-06-05 20:34:08 +0000231 uint32_t PlayoutTimestamp();
232
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000233 NetEq* neteq_;
234 FILE* rtp_fp_;
235 unsigned int sim_clock_;
236 int16_t out_data_[kMaxBlockSize];
237 int output_sample_rate_;
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +0000238 int algorithmic_delay_ms_;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000239};
240
241// Allocating the static const so that it can be passed by reference.
242const int NetEqDecodingTest::kTimeStepMs;
243const int NetEqDecodingTest::kBlockSize8kHz;
244const int NetEqDecodingTest::kBlockSize16kHz;
245const int NetEqDecodingTest::kBlockSize32kHz;
246const int NetEqDecodingTest::kMaxBlockSize;
247const int NetEqDecodingTest::kInitSampleRateHz;
248
249NetEqDecodingTest::NetEqDecodingTest()
250 : neteq_(NULL),
251 rtp_fp_(NULL),
252 sim_clock_(0),
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +0000253 output_sample_rate_(kInitSampleRateHz),
254 algorithmic_delay_ms_(0) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000255 memset(out_data_, 0, sizeof(out_data_));
256}
257
258void NetEqDecodingTest::SetUp() {
henrik.lundin@webrtc.org35ead382014-04-14 18:49:17 +0000259 NetEq::Config config;
260 config.sample_rate_hz = kInitSampleRateHz;
261 neteq_ = NetEq::Create(config);
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +0000262 NetEqNetworkStatistics stat;
263 ASSERT_EQ(0, neteq_->NetworkStatistics(&stat));
264 algorithmic_delay_ms_ = stat.current_buffer_size_ms;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000265 ASSERT_TRUE(neteq_);
266 LoadDecoders();
267}
268
269void NetEqDecodingTest::TearDown() {
270 delete neteq_;
271 if (rtp_fp_)
272 fclose(rtp_fp_);
273}
274
275void NetEqDecodingTest::LoadDecoders() {
276 // Load PCMu.
277 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCMu, 0));
278 // Load PCMa.
279 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCMa, 8));
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000280#ifndef WEBRTC_ANDROID
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000281 // Load iLBC.
282 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderILBC, 102));
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000283#endif // WEBRTC_ANDROID
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000284 // Load iSAC.
285 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISAC, 103));
turaj@webrtc.org5272eb82013-11-23 00:11:32 +0000286#ifndef WEBRTC_ANDROID
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000287 // Load iSAC SWB.
288 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACswb, 104));
henrik.lundin@webrtc.orgac59dba2013-01-31 09:55:24 +0000289 // Load iSAC FB.
290 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISACfb, 105));
turaj@webrtc.org5272eb82013-11-23 00:11:32 +0000291#endif // WEBRTC_ANDROID
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000292 // Load PCM16B nb.
293 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16B, 93));
294 // Load PCM16B wb.
295 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bwb, 94));
296 // Load PCM16B swb32.
297 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bswb32kHz, 95));
298 // Load CNG 8 kHz.
299 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGnb, 13));
300 // Load CNG 16 kHz.
301 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGwb, 98));
302}
303
304void NetEqDecodingTest::OpenInputFile(const std::string &rtp_file) {
305 rtp_fp_ = fopen(rtp_file.c_str(), "rb");
306 ASSERT_TRUE(rtp_fp_ != NULL);
307 ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp_));
308}
309
310void NetEqDecodingTest::Process(NETEQTEST_RTPpacket* rtp, int* out_len) {
311 // Check if time to receive.
312 while ((sim_clock_ >= rtp->time()) &&
313 (rtp->dataLen() >= 0)) {
314 if (rtp->dataLen() > 0) {
315 WebRtcRTPHeader rtpInfo;
316 rtp->parseHeader(&rtpInfo);
317 ASSERT_EQ(0, neteq_->InsertPacket(
318 rtpInfo,
319 rtp->payload(),
320 rtp->payloadLen(),
321 rtp->time() * (output_sample_rate_ / 1000)));
322 }
323 // Get next packet.
324 ASSERT_NE(-1, rtp->readFromFile(rtp_fp_));
325 }
326
henrik.lundin@webrtc.orge1d468c2013-01-30 07:37:20 +0000327 // Get audio from NetEq.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000328 NetEqOutputType type;
329 int num_channels;
330 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, out_len,
331 &num_channels, &type));
332 ASSERT_TRUE((*out_len == kBlockSize8kHz) ||
333 (*out_len == kBlockSize16kHz) ||
334 (*out_len == kBlockSize32kHz));
335 output_sample_rate_ = *out_len / 10 * 1000;
336
337 // Increase time.
338 sim_clock_ += kTimeStepMs;
339}
340
341void NetEqDecodingTest::DecodeAndCompare(const std::string &rtp_file,
342 const std::string &ref_file) {
343 OpenInputFile(rtp_file);
344
345 std::string ref_out_file = "";
346 if (ref_file.empty()) {
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000347 ref_out_file = webrtc::test::OutputPath() + "neteq_universal_ref.pcm";
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000348 }
349 RefFiles ref_files(ref_file, ref_out_file);
350
351 NETEQTEST_RTPpacket rtp;
352 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
353 int i = 0;
354 while (rtp.dataLen() >= 0) {
355 std::ostringstream ss;
356 ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
357 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
turaj@webrtc.org58cd3162013-10-31 15:15:55 +0000358 int out_len = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000359 ASSERT_NO_FATAL_FAILURE(Process(&rtp, &out_len));
360 ASSERT_NO_FATAL_FAILURE(ref_files.ProcessReference(out_data_, out_len));
361 }
362}
363
364void NetEqDecodingTest::DecodeAndCheckStats(const std::string &rtp_file,
365 const std::string &stat_ref_file,
366 const std::string &rtcp_ref_file) {
367 OpenInputFile(rtp_file);
368 std::string stat_out_file = "";
369 if (stat_ref_file.empty()) {
370 stat_out_file = webrtc::test::OutputPath() +
371 "neteq_network_stats.dat";
372 }
373 RefFiles network_stat_files(stat_ref_file, stat_out_file);
374
375 std::string rtcp_out_file = "";
376 if (rtcp_ref_file.empty()) {
377 rtcp_out_file = webrtc::test::OutputPath() +
378 "neteq_rtcp_stats.dat";
379 }
380 RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);
381
382 NETEQTEST_RTPpacket rtp;
383 ASSERT_GT(rtp.readFromFile(rtp_fp_), 0);
384 while (rtp.dataLen() >= 0) {
385 int out_len;
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000386 ASSERT_NO_FATAL_FAILURE(Process(&rtp, &out_len));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000387
388 // Query the network statistics API once per second
389 if (sim_clock_ % 1000 == 0) {
390 // Process NetworkStatistics.
391 NetEqNetworkStatistics network_stats;
392 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000393 ASSERT_NO_FATAL_FAILURE(
394 network_stat_files.ProcessReference(network_stats));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000395
396 // Process RTCPstat.
397 RtcpStatistics rtcp_stats;
398 neteq_->GetRtcpStatistics(&rtcp_stats);
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000399 ASSERT_NO_FATAL_FAILURE(rtcp_stat_files.ProcessReference(rtcp_stats));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000400 }
401 }
402}
403
404void NetEqDecodingTest::PopulateRtpInfo(int frame_index,
405 int timestamp,
406 WebRtcRTPHeader* rtp_info) {
407 rtp_info->header.sequenceNumber = frame_index;
408 rtp_info->header.timestamp = timestamp;
409 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
410 rtp_info->header.payloadType = 94; // PCM16b WB codec.
411 rtp_info->header.markerBit = 0;
412}
413
414void NetEqDecodingTest::PopulateCng(int frame_index,
415 int timestamp,
416 WebRtcRTPHeader* rtp_info,
417 uint8_t* payload,
418 int* payload_len) {
419 rtp_info->header.sequenceNumber = frame_index;
420 rtp_info->header.timestamp = timestamp;
421 rtp_info->header.ssrc = 0x1234; // Just an arbitrary SSRC.
422 rtp_info->header.payloadType = 98; // WB CNG.
423 rtp_info->header.markerBit = 0;
424 payload[0] = 64; // Noise level -64 dBov, quite arbitrarily chosen.
425 *payload_len = 1; // Only noise level, no spectral parameters.
426}
427
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000428void NetEqDecodingTest::CheckBgnOff(int sampling_rate_hz,
429 NetEqBackgroundNoiseMode bgn_mode) {
430 int expected_samples_per_channel = 0;
431 uint8_t payload_type = 0xFF; // Invalid.
432 if (sampling_rate_hz == 8000) {
433 expected_samples_per_channel = kBlockSize8kHz;
434 payload_type = 93; // PCM 16, 8 kHz.
435 } else if (sampling_rate_hz == 16000) {
436 expected_samples_per_channel = kBlockSize16kHz;
437 payload_type = 94; // PCM 16, 16 kHZ.
438 } else if (sampling_rate_hz == 32000) {
439 expected_samples_per_channel = kBlockSize32kHz;
440 payload_type = 95; // PCM 16, 32 kHz.
441 } else {
442 ASSERT_TRUE(false); // Unsupported test case.
443 }
444
445 NetEqOutputType type;
446 int16_t output[kBlockSize32kHz]; // Maximum size is chosen.
447 int16_t input[kBlockSize32kHz]; // Maximum size is chosen.
448
449 // Payload of 10 ms of PCM16 32 kHz.
450 uint8_t payload[kBlockSize32kHz * sizeof(int16_t)];
451
452 // Random payload.
453 for (int n = 0; n < expected_samples_per_channel; ++n) {
454 input[n] = (rand() & ((1 << 10) - 1)) - ((1 << 5) - 1);
455 }
456 int enc_len_bytes = WebRtcPcm16b_EncodeW16(
457 input, expected_samples_per_channel, reinterpret_cast<int16_t*>(payload));
458 ASSERT_EQ(enc_len_bytes, expected_samples_per_channel * 2);
459
460 WebRtcRTPHeader rtp_info;
461 PopulateRtpInfo(0, 0, &rtp_info);
462 rtp_info.header.payloadType = payload_type;
463
464 int number_channels = 0;
465 int samples_per_channel = 0;
466
467 uint32_t receive_timestamp = 0;
468 for (int n = 0; n < 10; ++n) { // Insert few packets and get audio.
469 number_channels = 0;
470 samples_per_channel = 0;
471 ASSERT_EQ(0, neteq_->InsertPacket(
472 rtp_info, payload, enc_len_bytes, receive_timestamp));
473 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
474 &number_channels, &type));
475 ASSERT_EQ(1, number_channels);
476 ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
477 ASSERT_EQ(kOutputNormal, type);
478
479 // Next packet.
480 rtp_info.header.timestamp += expected_samples_per_channel;
481 rtp_info.header.sequenceNumber++;
482 receive_timestamp += expected_samples_per_channel;
483 }
484
485 number_channels = 0;
486 samples_per_channel = 0;
487
488 // Get audio without inserting packets, expecting PLC and PLC-to-CNG. Pull one
489 // frame without checking speech-type. This is the first frame pulled without
490 // inserting any packet, and might not be labeled as PCL.
491 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
492 &number_channels, &type));
493 ASSERT_EQ(1, number_channels);
494 ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
495
496 // To be able to test the fading of background noise we need at lease to pull
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +0000497 // 611 frames.
498 const int kFadingThreshold = 611;
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000499
500 // Test several CNG-to-PLC packet for the expected behavior. The number 20 is
501 // arbitrary, but sufficiently large to test enough number of frames.
502 const int kNumPlcToCngTestFrames = 20;
503 bool plc_to_cng = false;
504 for (int n = 0; n < kFadingThreshold + kNumPlcToCngTestFrames; ++n) {
505 number_channels = 0;
506 samples_per_channel = 0;
507 memset(output, 1, sizeof(output)); // Set to non-zero.
508 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
509 &number_channels, &type));
510 ASSERT_EQ(1, number_channels);
511 ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
512 if (type == kOutputPLCtoCNG) {
513 plc_to_cng = true;
514 double sum_squared = 0;
515 for (int k = 0; k < number_channels * samples_per_channel; ++k)
516 sum_squared += output[k] * output[k];
517 if (bgn_mode == kBgnOn) {
518 EXPECT_NE(0, sum_squared);
519 } else if (bgn_mode == kBgnOff || n > kFadingThreshold) {
520 EXPECT_EQ(0, sum_squared);
521 }
522 } else {
523 EXPECT_EQ(kOutputPLC, type);
524 }
525 }
526 EXPECT_TRUE(plc_to_cng); // Just to be sure that PLC-to-CNG has occurred.
527}
528
henrik.lundin@webrtc.org48438c22014-05-20 16:07:43 +0000529TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(TestBitExactness)) {
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000530 const std::string input_rtp_file = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000531 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org48438c22014-05-20 16:07:43 +0000532 // Note that neteq4_universal_ref.pcm and neteq4_universal_ref_win_32.pcm
533 // are identical. The latter could have been removed, but if clients still
534 // have a copy of the file, the test will fail.
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000535 const std::string input_ref_file =
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000536 webrtc::test::ResourcePath("audio_coding/neteq4_universal_ref", "pcm");
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000537
538 if (FLAGS_gen_ref) {
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000539 DecodeAndCompare(input_rtp_file, "");
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000540 } else {
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000541 DecodeAndCompare(input_rtp_file, input_ref_file);
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000542 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000543}
544
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000545TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(TestNetworkStatistics)) {
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000546 const std::string input_rtp_file = webrtc::test::ProjectRootPath() +
henrik.lundin@webrtc.org73deaad2013-01-31 13:32:51 +0000547 "resources/audio_coding/neteq_universal_new.rtp";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000548#if defined(_MSC_VER) && (_MSC_VER >= 1700)
549 // For Visual Studio 2012 and later, we will have to use the generic reference
550 // file, rather than the windows-specific one.
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000551 const std::string network_stat_ref_file = webrtc::test::ProjectRootPath() +
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000552 "resources/audio_coding/neteq4_network_stats.dat";
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000553#else
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000554 const std::string network_stat_ref_file =
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000555 webrtc::test::ResourcePath("audio_coding/neteq4_network_stats", "dat");
henrik.lundin@webrtc.org6e3968f2013-01-31 15:07:30 +0000556#endif
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000557 const std::string rtcp_stat_ref_file =
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000558 webrtc::test::ResourcePath("audio_coding/neteq4_rtcp_stats", "dat");
559 if (FLAGS_gen_ref) {
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000560 DecodeAndCheckStats(input_rtp_file, "", "");
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000561 } else {
andrew@webrtc.orgf6a638e2014-02-04 01:31:28 +0000562 DecodeAndCheckStats(input_rtp_file, network_stat_ref_file,
563 rtcp_stat_ref_file);
turaj@webrtc.orga6101d72013-10-01 22:01:09 +0000564 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000565}
566
567// TODO(hlundin): Re-enable test once the statistics interface is up and again.
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000568TEST_F(NetEqDecodingTest, TestFrameWaitingTimeStatistics) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000569 // Use fax mode to avoid time-scaling. This is to simplify the testing of
570 // packet waiting times in the packet buffer.
571 neteq_->SetPlayoutMode(kPlayoutFax);
572 ASSERT_EQ(kPlayoutFax, neteq_->PlayoutMode());
573 // Insert 30 dummy packets at once. Each packet contains 10 ms 16 kHz audio.
574 size_t num_frames = 30;
575 const int kSamples = 10 * 16;
576 const int kPayloadBytes = kSamples * 2;
577 for (size_t i = 0; i < num_frames; ++i) {
578 uint16_t payload[kSamples] = {0};
579 WebRtcRTPHeader rtp_info;
580 rtp_info.header.sequenceNumber = i;
581 rtp_info.header.timestamp = i * kSamples;
582 rtp_info.header.ssrc = 0x1234; // Just an arbitrary SSRC.
583 rtp_info.header.payloadType = 94; // PCM16b WB codec.
584 rtp_info.header.markerBit = 0;
585 ASSERT_EQ(0, neteq_->InsertPacket(
586 rtp_info,
587 reinterpret_cast<uint8_t*>(payload),
588 kPayloadBytes, 0));
589 }
590 // Pull out all data.
591 for (size_t i = 0; i < num_frames; ++i) {
592 int out_len;
593 int num_channels;
594 NetEqOutputType type;
595 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
596 &num_channels, &type));
597 ASSERT_EQ(kBlockSize16kHz, out_len);
598 }
599
600 std::vector<int> waiting_times;
601 neteq_->WaitingTimes(&waiting_times);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000602 EXPECT_EQ(num_frames, waiting_times.size());
603 // Since all frames are dumped into NetEQ at once, but pulled out with 10 ms
604 // spacing (per definition), we expect the delay to increase with 10 ms for
605 // each packet.
606 for (size_t i = 0; i < waiting_times.size(); ++i) {
607 EXPECT_EQ(static_cast<int>(i + 1) * 10, waiting_times[i]);
608 }
609
610 // Check statistics again and make sure it's been reset.
611 neteq_->WaitingTimes(&waiting_times);
turaj@webrtc.org58cd3162013-10-31 15:15:55 +0000612 int len = waiting_times.size();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000613 EXPECT_EQ(0, len);
614
615 // Process > 100 frames, and make sure that that we get statistics
616 // only for 100 frames. Note the new SSRC, causing NetEQ to reset.
617 num_frames = 110;
618 for (size_t i = 0; i < num_frames; ++i) {
619 uint16_t payload[kSamples] = {0};
620 WebRtcRTPHeader rtp_info;
621 rtp_info.header.sequenceNumber = i;
622 rtp_info.header.timestamp = i * kSamples;
623 rtp_info.header.ssrc = 0x1235; // Just an arbitrary SSRC.
624 rtp_info.header.payloadType = 94; // PCM16b WB codec.
625 rtp_info.header.markerBit = 0;
626 ASSERT_EQ(0, neteq_->InsertPacket(
627 rtp_info,
628 reinterpret_cast<uint8_t*>(payload),
629 kPayloadBytes, 0));
630 int out_len;
631 int num_channels;
632 NetEqOutputType type;
633 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
634 &num_channels, &type));
635 ASSERT_EQ(kBlockSize16kHz, out_len);
636 }
637
638 neteq_->WaitingTimes(&waiting_times);
639 EXPECT_EQ(100u, waiting_times.size());
640}
641
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000642TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimeNegative) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000643 const int kNumFrames = 3000; // Needed for convergence.
644 int frame_index = 0;
645 const int kSamples = 10 * 16;
646 const int kPayloadBytes = kSamples * 2;
647 while (frame_index < kNumFrames) {
648 // Insert one packet each time, except every 10th time where we insert two
649 // packets at once. This will create a negative clock-drift of approx. 10%.
650 int num_packets = (frame_index % 10 == 0 ? 2 : 1);
651 for (int n = 0; n < num_packets; ++n) {
652 uint8_t payload[kPayloadBytes] = {0};
653 WebRtcRTPHeader rtp_info;
654 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
655 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
656 ++frame_index;
657 }
658
659 // Pull out data once.
660 int out_len;
661 int num_channels;
662 NetEqOutputType type;
663 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
664 &num_channels, &type));
665 ASSERT_EQ(kBlockSize16kHz, out_len);
666 }
667
668 NetEqNetworkStatistics network_stats;
669 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
670 EXPECT_EQ(-103196, network_stats.clockdrift_ppm);
671}
672
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000673TEST_F(NetEqDecodingTest, TestAverageInterArrivalTimePositive) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000674 const int kNumFrames = 5000; // Needed for convergence.
675 int frame_index = 0;
676 const int kSamples = 10 * 16;
677 const int kPayloadBytes = kSamples * 2;
678 for (int i = 0; i < kNumFrames; ++i) {
679 // Insert one packet each time, except every 10th time where we don't insert
680 // any packet. This will create a positive clock-drift of approx. 11%.
681 int num_packets = (i % 10 == 9 ? 0 : 1);
682 for (int n = 0; n < num_packets; ++n) {
683 uint8_t payload[kPayloadBytes] = {0};
684 WebRtcRTPHeader rtp_info;
685 PopulateRtpInfo(frame_index, frame_index * kSamples, &rtp_info);
686 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
687 ++frame_index;
688 }
689
690 // Pull out data once.
691 int out_len;
692 int num_channels;
693 NetEqOutputType type;
694 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
695 &num_channels, &type));
696 ASSERT_EQ(kBlockSize16kHz, out_len);
697 }
698
699 NetEqNetworkStatistics network_stats;
700 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
701 EXPECT_EQ(110946, network_stats.clockdrift_ppm);
702}
703
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000704void NetEqDecodingTest::LongCngWithClockDrift(double drift_factor,
705 double network_freeze_ms,
706 bool pull_audio_during_freeze,
707 int delay_tolerance_ms,
708 int max_time_to_speech_ms) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000709 uint16_t seq_no = 0;
710 uint32_t timestamp = 0;
711 const int kFrameSizeMs = 30;
712 const int kSamples = kFrameSizeMs * 16;
713 const int kPayloadBytes = kSamples * 2;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000714 double next_input_time_ms = 0.0;
715 double t_ms;
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000716 int out_len;
717 int num_channels;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000718 NetEqOutputType type;
719
720 // Insert speech for 5 seconds.
721 const int kSpeechDurationMs = 5000;
722 for (t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
723 // Each turn in this for loop is 10 ms.
724 while (next_input_time_ms <= t_ms) {
725 // Insert one 30 ms speech frame.
726 uint8_t payload[kPayloadBytes] = {0};
727 WebRtcRTPHeader rtp_info;
728 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
729 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
730 ++seq_no;
731 timestamp += kSamples;
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000732 next_input_time_ms += static_cast<double>(kFrameSizeMs) * drift_factor;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000733 }
734 // Pull out data once.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000735 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
736 &num_channels, &type));
737 ASSERT_EQ(kBlockSize16kHz, out_len);
738 }
739
740 EXPECT_EQ(kOutputNormal, type);
wu@webrtc.org94454b72014-06-05 20:34:08 +0000741 int32_t delay_before = timestamp - PlayoutTimestamp();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000742
743 // Insert CNG for 1 minute (= 60000 ms).
744 const int kCngPeriodMs = 100;
745 const int kCngPeriodSamples = kCngPeriodMs * 16; // Period in 16 kHz samples.
746 const int kCngDurationMs = 60000;
747 for (; t_ms < kSpeechDurationMs + kCngDurationMs; t_ms += 10) {
748 // Each turn in this for loop is 10 ms.
749 while (next_input_time_ms <= t_ms) {
750 // Insert one CNG frame each 100 ms.
751 uint8_t payload[kPayloadBytes];
752 int payload_len;
753 WebRtcRTPHeader rtp_info;
754 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
755 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
756 ++seq_no;
757 timestamp += kCngPeriodSamples;
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000758 next_input_time_ms += static_cast<double>(kCngPeriodMs) * drift_factor;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000759 }
760 // Pull out data once.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000761 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
762 &num_channels, &type));
763 ASSERT_EQ(kBlockSize16kHz, out_len);
764 }
765
766 EXPECT_EQ(kOutputCNG, type);
767
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000768 if (network_freeze_ms > 0) {
769 // First keep pulling audio for |network_freeze_ms| without inserting
770 // any data, then insert CNG data corresponding to |network_freeze_ms|
771 // without pulling any output audio.
772 const double loop_end_time = t_ms + network_freeze_ms;
773 for (; t_ms < loop_end_time; t_ms += 10) {
774 // Pull out data once.
775 ASSERT_EQ(0,
776 neteq_->GetAudio(
777 kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
778 ASSERT_EQ(kBlockSize16kHz, out_len);
779 EXPECT_EQ(kOutputCNG, type);
780 }
781 bool pull_once = pull_audio_during_freeze;
782 // If |pull_once| is true, GetAudio will be called once half-way through
783 // the network recovery period.
784 double pull_time_ms = (t_ms + next_input_time_ms) / 2;
785 while (next_input_time_ms <= t_ms) {
786 if (pull_once && next_input_time_ms >= pull_time_ms) {
787 pull_once = false;
788 // Pull out data once.
789 ASSERT_EQ(
790 0,
791 neteq_->GetAudio(
792 kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
793 ASSERT_EQ(kBlockSize16kHz, out_len);
794 EXPECT_EQ(kOutputCNG, type);
795 t_ms += 10;
796 }
797 // Insert one CNG frame each 100 ms.
798 uint8_t payload[kPayloadBytes];
799 int payload_len;
800 WebRtcRTPHeader rtp_info;
801 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
802 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
803 ++seq_no;
804 timestamp += kCngPeriodSamples;
805 next_input_time_ms += kCngPeriodMs * drift_factor;
806 }
807 }
808
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000809 // Insert speech again until output type is speech.
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000810 double speech_restart_time_ms = t_ms;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000811 while (type != kOutputNormal) {
812 // Each turn in this for loop is 10 ms.
813 while (next_input_time_ms <= t_ms) {
814 // Insert one 30 ms speech frame.
815 uint8_t payload[kPayloadBytes] = {0};
816 WebRtcRTPHeader rtp_info;
817 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
818 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
819 ++seq_no;
820 timestamp += kSamples;
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000821 next_input_time_ms += kFrameSizeMs * drift_factor;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000822 }
823 // Pull out data once.
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000824 ASSERT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_, &out_len,
825 &num_channels, &type));
826 ASSERT_EQ(kBlockSize16kHz, out_len);
827 // Increase clock.
828 t_ms += 10;
829 }
830
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000831 // Check that the speech starts again within reasonable time.
832 double time_until_speech_returns_ms = t_ms - speech_restart_time_ms;
833 EXPECT_LT(time_until_speech_returns_ms, max_time_to_speech_ms);
wu@webrtc.org94454b72014-06-05 20:34:08 +0000834 int32_t delay_after = timestamp - PlayoutTimestamp();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000835 // Compare delay before and after, and make sure it differs less than 20 ms.
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000836 EXPECT_LE(delay_after, delay_before + delay_tolerance_ms * 16);
837 EXPECT_GE(delay_after, delay_before - delay_tolerance_ms * 16);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000838}
839
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000840TEST_F(NetEqDecodingTest, LongCngWithNegativeClockDrift) {
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000841 // Apply a clock drift of -25 ms / s (sender faster than receiver).
842 const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000843 const double kNetworkFreezeTimeMs = 0.0;
844 const bool kGetAudioDuringFreezeRecovery = false;
845 const int kDelayToleranceMs = 20;
846 const int kMaxTimeToSpeechMs = 100;
847 LongCngWithClockDrift(kDriftFactor,
848 kNetworkFreezeTimeMs,
849 kGetAudioDuringFreezeRecovery,
850 kDelayToleranceMs,
851 kMaxTimeToSpeechMs);
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000852}
853
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000854TEST_F(NetEqDecodingTest, LongCngWithPositiveClockDrift) {
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000855 // Apply a clock drift of +25 ms / s (sender slower than receiver).
856 const double kDriftFactor = 1000.0 / (1000.0 - 25.0);
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000857 const double kNetworkFreezeTimeMs = 0.0;
858 const bool kGetAudioDuringFreezeRecovery = false;
859 const int kDelayToleranceMs = 20;
860 const int kMaxTimeToSpeechMs = 100;
861 LongCngWithClockDrift(kDriftFactor,
862 kNetworkFreezeTimeMs,
863 kGetAudioDuringFreezeRecovery,
864 kDelayToleranceMs,
865 kMaxTimeToSpeechMs);
866}
867
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000868TEST_F(NetEqDecodingTest, LongCngWithNegativeClockDriftNetworkFreeze) {
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000869 // Apply a clock drift of -25 ms / s (sender faster than receiver).
870 const double kDriftFactor = 1000.0 / (1000.0 + 25.0);
871 const double kNetworkFreezeTimeMs = 5000.0;
872 const bool kGetAudioDuringFreezeRecovery = false;
873 const int kDelayToleranceMs = 50;
874 const int kMaxTimeToSpeechMs = 200;
875 LongCngWithClockDrift(kDriftFactor,
876 kNetworkFreezeTimeMs,
877 kGetAudioDuringFreezeRecovery,
878 kDelayToleranceMs,
879 kMaxTimeToSpeechMs);
880}
881
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000882TEST_F(NetEqDecodingTest, LongCngWithPositiveClockDriftNetworkFreeze) {
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000883 // Apply a clock drift of +25 ms / s (sender slower than receiver).
884 const double kDriftFactor = 1000.0 / (1000.0 - 25.0);
885 const double kNetworkFreezeTimeMs = 5000.0;
886 const bool kGetAudioDuringFreezeRecovery = false;
887 const int kDelayToleranceMs = 20;
888 const int kMaxTimeToSpeechMs = 100;
889 LongCngWithClockDrift(kDriftFactor,
890 kNetworkFreezeTimeMs,
891 kGetAudioDuringFreezeRecovery,
892 kDelayToleranceMs,
893 kMaxTimeToSpeechMs);
894}
895
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000896TEST_F(NetEqDecodingTest, LongCngWithPositiveClockDriftNetworkFreezeExtraPull) {
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000897 // Apply a clock drift of +25 ms / s (sender slower than receiver).
898 const double kDriftFactor = 1000.0 / (1000.0 - 25.0);
899 const double kNetworkFreezeTimeMs = 5000.0;
900 const bool kGetAudioDuringFreezeRecovery = true;
901 const int kDelayToleranceMs = 20;
902 const int kMaxTimeToSpeechMs = 100;
903 LongCngWithClockDrift(kDriftFactor,
904 kNetworkFreezeTimeMs,
905 kGetAudioDuringFreezeRecovery,
906 kDelayToleranceMs,
907 kMaxTimeToSpeechMs);
908}
909
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000910TEST_F(NetEqDecodingTest, LongCngWithoutClockDrift) {
henrik.lundin@webrtc.org24779fe2014-03-14 12:40:05 +0000911 const double kDriftFactor = 1.0; // No drift.
912 const double kNetworkFreezeTimeMs = 0.0;
913 const bool kGetAudioDuringFreezeRecovery = false;
914 const int kDelayToleranceMs = 10;
915 const int kMaxTimeToSpeechMs = 50;
916 LongCngWithClockDrift(kDriftFactor,
917 kNetworkFreezeTimeMs,
918 kGetAudioDuringFreezeRecovery,
919 kDelayToleranceMs,
920 kMaxTimeToSpeechMs);
henrik.lundin@webrtc.orgfcfc6a92014-02-13 11:42:28 +0000921}
922
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000923TEST_F(NetEqDecodingTest, UnknownPayloadType) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000924 const int kPayloadBytes = 100;
925 uint8_t payload[kPayloadBytes] = {0};
926 WebRtcRTPHeader rtp_info;
927 PopulateRtpInfo(0, 0, &rtp_info);
928 rtp_info.header.payloadType = 1; // Not registered as a decoder.
929 EXPECT_EQ(NetEq::kFail,
930 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
931 EXPECT_EQ(NetEq::kUnknownRtpPayloadType, neteq_->LastError());
932}
933
henrike@webrtc.orga950300b2013-07-08 18:53:54 +0000934TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(DecoderError)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000935 const int kPayloadBytes = 100;
936 uint8_t payload[kPayloadBytes] = {0};
937 WebRtcRTPHeader rtp_info;
938 PopulateRtpInfo(0, 0, &rtp_info);
939 rtp_info.header.payloadType = 103; // iSAC, but the payload is invalid.
940 EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
941 NetEqOutputType type;
942 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
943 // to GetAudio.
944 for (int i = 0; i < kMaxBlockSize; ++i) {
945 out_data_[i] = 1;
946 }
947 int num_channels;
948 int samples_per_channel;
949 EXPECT_EQ(NetEq::kFail,
950 neteq_->GetAudio(kMaxBlockSize, out_data_,
951 &samples_per_channel, &num_channels, &type));
952 // Verify that there is a decoder error to check.
953 EXPECT_EQ(NetEq::kDecoderErrorCode, neteq_->LastError());
954 // Code 6730 is an iSAC error code.
955 EXPECT_EQ(6730, neteq_->LastDecoderError());
956 // Verify that the first 160 samples are set to 0, and that the remaining
957 // samples are left unmodified.
958 static const int kExpectedOutputLength = 160; // 10 ms at 16 kHz sample rate.
959 for (int i = 0; i < kExpectedOutputLength; ++i) {
960 std::ostringstream ss;
961 ss << "i = " << i;
962 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
963 EXPECT_EQ(0, out_data_[i]);
964 }
965 for (int i = kExpectedOutputLength; i < kMaxBlockSize; ++i) {
966 std::ostringstream ss;
967 ss << "i = " << i;
968 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
969 EXPECT_EQ(1, out_data_[i]);
970 }
971}
972
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000973TEST_F(NetEqDecodingTest, GetAudioBeforeInsertPacket) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000974 NetEqOutputType type;
975 // Set all of |out_data_| to 1, and verify that it was set to 0 by the call
976 // to GetAudio.
977 for (int i = 0; i < kMaxBlockSize; ++i) {
978 out_data_[i] = 1;
979 }
980 int num_channels;
981 int samples_per_channel;
982 EXPECT_EQ(0, neteq_->GetAudio(kMaxBlockSize, out_data_,
983 &samples_per_channel,
984 &num_channels, &type));
985 // Verify that the first block of samples is set to 0.
986 static const int kExpectedOutputLength =
987 kInitSampleRateHz / 100; // 10 ms at initial sample rate.
988 for (int i = 0; i < kExpectedOutputLength; ++i) {
989 std::ostringstream ss;
990 ss << "i = " << i;
991 SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
992 EXPECT_EQ(0, out_data_[i]);
993 }
994}
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000995
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +0000996TEST_F(NetEqDecodingTest, BackgroundNoise) {
turaj@webrtc.orgff43c852013-09-25 00:07:27 +0000997 neteq_->SetBackgroundNoiseMode(kBgnOn);
998 CheckBgnOff(8000, kBgnOn);
999 CheckBgnOff(16000, kBgnOn);
1000 CheckBgnOff(32000, kBgnOn);
1001 EXPECT_EQ(kBgnOn, neteq_->BackgroundNoiseMode());
1002
1003 neteq_->SetBackgroundNoiseMode(kBgnOff);
1004 CheckBgnOff(8000, kBgnOff);
1005 CheckBgnOff(16000, kBgnOff);
1006 CheckBgnOff(32000, kBgnOff);
1007 EXPECT_EQ(kBgnOff, neteq_->BackgroundNoiseMode());
1008
1009 neteq_->SetBackgroundNoiseMode(kBgnFade);
1010 CheckBgnOff(8000, kBgnFade);
1011 CheckBgnOff(16000, kBgnFade);
1012 CheckBgnOff(32000, kBgnFade);
1013 EXPECT_EQ(kBgnFade, neteq_->BackgroundNoiseMode());
1014}
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001015
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +00001016TEST_F(NetEqDecodingTest, SyncPacketInsert) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001017 WebRtcRTPHeader rtp_info;
1018 uint32_t receive_timestamp = 0;
1019 // For the readability use the following payloads instead of the defaults of
1020 // this test.
1021 uint8_t kPcm16WbPayloadType = 1;
1022 uint8_t kCngNbPayloadType = 2;
1023 uint8_t kCngWbPayloadType = 3;
1024 uint8_t kCngSwb32PayloadType = 4;
1025 uint8_t kCngSwb48PayloadType = 5;
1026 uint8_t kAvtPayloadType = 6;
1027 uint8_t kRedPayloadType = 7;
1028 uint8_t kIsacPayloadType = 9; // Payload type 8 is already registered.
1029
1030 // Register decoders.
1031 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderPCM16Bwb,
1032 kPcm16WbPayloadType));
1033 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGnb, kCngNbPayloadType));
1034 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGwb, kCngWbPayloadType));
1035 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGswb32kHz,
1036 kCngSwb32PayloadType));
1037 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderCNGswb48kHz,
1038 kCngSwb48PayloadType));
1039 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderAVT, kAvtPayloadType));
1040 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderRED, kRedPayloadType));
1041 ASSERT_EQ(0, neteq_->RegisterPayloadType(kDecoderISAC, kIsacPayloadType));
1042
1043 PopulateRtpInfo(0, 0, &rtp_info);
1044 rtp_info.header.payloadType = kPcm16WbPayloadType;
1045
1046 // The first packet injected cannot be sync-packet.
1047 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1048
1049 // Payload length of 10 ms PCM16 16 kHz.
1050 const int kPayloadBytes = kBlockSize16kHz * sizeof(int16_t);
1051 uint8_t payload[kPayloadBytes] = {0};
1052 ASSERT_EQ(0, neteq_->InsertPacket(
1053 rtp_info, payload, kPayloadBytes, receive_timestamp));
1054
1055 // Next packet. Last packet contained 10 ms audio.
1056 rtp_info.header.sequenceNumber++;
1057 rtp_info.header.timestamp += kBlockSize16kHz;
1058 receive_timestamp += kBlockSize16kHz;
1059
1060 // Unacceptable payload types CNG, AVT (DTMF), RED.
1061 rtp_info.header.payloadType = kCngNbPayloadType;
1062 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1063
1064 rtp_info.header.payloadType = kCngWbPayloadType;
1065 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1066
1067 rtp_info.header.payloadType = kCngSwb32PayloadType;
1068 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1069
1070 rtp_info.header.payloadType = kCngSwb48PayloadType;
1071 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1072
1073 rtp_info.header.payloadType = kAvtPayloadType;
1074 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1075
1076 rtp_info.header.payloadType = kRedPayloadType;
1077 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1078
1079 // Change of codec cannot be initiated with a sync packet.
1080 rtp_info.header.payloadType = kIsacPayloadType;
1081 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1082
1083 // Change of SSRC is not allowed with a sync packet.
1084 rtp_info.header.payloadType = kPcm16WbPayloadType;
1085 ++rtp_info.header.ssrc;
1086 EXPECT_EQ(-1, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1087
1088 --rtp_info.header.ssrc;
1089 EXPECT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1090}
1091
1092// First insert several noise like packets, then sync-packets. Decoding all
1093// packets should not produce error, statistics should not show any packet loss
1094// and sync-packets should decode to zero.
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001095// TODO(turajs) we will have a better test if we have a referece NetEq, and
1096// when Sync packets are inserted in "test" NetEq we insert all-zero payload
1097// in reference NetEq and compare the output of those two.
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +00001098TEST_F(NetEqDecodingTest, SyncPacketDecode) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001099 WebRtcRTPHeader rtp_info;
1100 PopulateRtpInfo(0, 0, &rtp_info);
1101 const int kPayloadBytes = kBlockSize16kHz * sizeof(int16_t);
1102 uint8_t payload[kPayloadBytes];
1103 int16_t decoded[kBlockSize16kHz];
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001104 int algorithmic_frame_delay = algorithmic_delay_ms_ / 10 + 1;
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001105 for (int n = 0; n < kPayloadBytes; ++n) {
1106 payload[n] = (rand() & 0xF0) + 1; // Non-zero random sequence.
1107 }
1108 // Insert some packets which decode to noise. We are not interested in
1109 // actual decoded values.
1110 NetEqOutputType output_type;
1111 int num_channels;
1112 int samples_per_channel;
1113 uint32_t receive_timestamp = 0;
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001114 for (int n = 0; n < 100; ++n) {
1115 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes,
1116 receive_timestamp));
1117 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize16kHz, decoded,
1118 &samples_per_channel, &num_channels,
1119 &output_type));
1120 ASSERT_EQ(kBlockSize16kHz, samples_per_channel);
1121 ASSERT_EQ(1, num_channels);
1122
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001123 rtp_info.header.sequenceNumber++;
1124 rtp_info.header.timestamp += kBlockSize16kHz;
1125 receive_timestamp += kBlockSize16kHz;
1126 }
1127 const int kNumSyncPackets = 10;
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001128
1129 // Make sure sufficient number of sync packets are inserted that we can
1130 // conduct a test.
1131 ASSERT_GT(kNumSyncPackets, algorithmic_frame_delay);
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001132 // Insert sync-packets, the decoded sequence should be all-zero.
1133 for (int n = 0; n < kNumSyncPackets; ++n) {
1134 ASSERT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1135 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize16kHz, decoded,
1136 &samples_per_channel, &num_channels,
1137 &output_type));
1138 ASSERT_EQ(kBlockSize16kHz, samples_per_channel);
1139 ASSERT_EQ(1, num_channels);
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001140 if (n > algorithmic_frame_delay) {
1141 EXPECT_TRUE(IsAllZero(decoded, samples_per_channel * num_channels));
1142 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001143 rtp_info.header.sequenceNumber++;
1144 rtp_info.header.timestamp += kBlockSize16kHz;
1145 receive_timestamp += kBlockSize16kHz;
1146 }
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001147
1148 // We insert regular packets, if sync packet are not correctly buffered then
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001149 // network statistics would show some packet loss.
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001150 for (int n = 0; n <= algorithmic_frame_delay + 10; ++n) {
1151 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes,
1152 receive_timestamp));
1153 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize16kHz, decoded,
1154 &samples_per_channel, &num_channels,
1155 &output_type));
1156 if (n >= algorithmic_frame_delay + 1) {
1157 // Expect that this frame contain samples from regular RTP.
1158 EXPECT_TRUE(IsAllNonZero(decoded, samples_per_channel * num_channels));
1159 }
1160 rtp_info.header.sequenceNumber++;
1161 rtp_info.header.timestamp += kBlockSize16kHz;
1162 receive_timestamp += kBlockSize16kHz;
1163 }
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001164 NetEqNetworkStatistics network_stats;
1165 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
1166 // Expecting a "clean" network.
1167 EXPECT_EQ(0, network_stats.packet_loss_rate);
1168 EXPECT_EQ(0, network_stats.expand_rate);
1169 EXPECT_EQ(0, network_stats.accelerate_rate);
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001170 EXPECT_LE(network_stats.preemptive_rate, 150);
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001171}
1172
1173// Test if the size of the packet buffer reported correctly when containing
1174// sync packets. Also, test if network packets override sync packets. That is to
1175// prefer decoding a network packet to a sync packet, if both have same sequence
1176// number and timestamp.
henrik.lundin@webrtc.orgb4e80e02014-05-15 07:14:00 +00001177TEST_F(NetEqDecodingTest, SyncPacketBufferSizeAndOverridenByNetworkPackets) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001178 WebRtcRTPHeader rtp_info;
1179 PopulateRtpInfo(0, 0, &rtp_info);
1180 const int kPayloadBytes = kBlockSize16kHz * sizeof(int16_t);
1181 uint8_t payload[kPayloadBytes];
1182 int16_t decoded[kBlockSize16kHz];
1183 for (int n = 0; n < kPayloadBytes; ++n) {
1184 payload[n] = (rand() & 0xF0) + 1; // Non-zero random sequence.
1185 }
1186 // Insert some packets which decode to noise. We are not interested in
1187 // actual decoded values.
1188 NetEqOutputType output_type;
1189 int num_channels;
1190 int samples_per_channel;
1191 uint32_t receive_timestamp = 0;
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001192 int algorithmic_frame_delay = algorithmic_delay_ms_ / 10 + 1;
1193 for (int n = 0; n < algorithmic_frame_delay; ++n) {
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001194 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes,
1195 receive_timestamp));
1196 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize16kHz, decoded,
1197 &samples_per_channel, &num_channels,
1198 &output_type));
1199 ASSERT_EQ(kBlockSize16kHz, samples_per_channel);
1200 ASSERT_EQ(1, num_channels);
1201 rtp_info.header.sequenceNumber++;
1202 rtp_info.header.timestamp += kBlockSize16kHz;
1203 receive_timestamp += kBlockSize16kHz;
1204 }
1205 const int kNumSyncPackets = 10;
1206
1207 WebRtcRTPHeader first_sync_packet_rtp_info;
1208 memcpy(&first_sync_packet_rtp_info, &rtp_info, sizeof(rtp_info));
1209
1210 // Insert sync-packets, but no decoding.
1211 for (int n = 0; n < kNumSyncPackets; ++n) {
1212 ASSERT_EQ(0, neteq_->InsertSyncPacket(rtp_info, receive_timestamp));
1213 rtp_info.header.sequenceNumber++;
1214 rtp_info.header.timestamp += kBlockSize16kHz;
1215 receive_timestamp += kBlockSize16kHz;
1216 }
1217 NetEqNetworkStatistics network_stats;
1218 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001219 EXPECT_EQ(kNumSyncPackets * 10 + algorithmic_delay_ms_,
1220 network_stats.current_buffer_size_ms);
turaj@webrtc.org7b75ac62013-09-26 00:27:56 +00001221
1222 // Rewind |rtp_info| to that of the first sync packet.
1223 memcpy(&rtp_info, &first_sync_packet_rtp_info, sizeof(rtp_info));
1224
1225 // Insert.
1226 for (int n = 0; n < kNumSyncPackets; ++n) {
1227 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes,
1228 receive_timestamp));
1229 rtp_info.header.sequenceNumber++;
1230 rtp_info.header.timestamp += kBlockSize16kHz;
1231 receive_timestamp += kBlockSize16kHz;
1232 }
1233
1234 // Decode.
1235 for (int n = 0; n < kNumSyncPackets; ++n) {
1236 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize16kHz, decoded,
1237 &samples_per_channel, &num_channels,
1238 &output_type));
1239 ASSERT_EQ(kBlockSize16kHz, samples_per_channel);
1240 ASSERT_EQ(1, num_channels);
1241 EXPECT_TRUE(IsAllNonZero(decoded, samples_per_channel * num_channels));
1242 }
1243}
1244
turaj@webrtc.org78b41a02013-11-22 20:27:07 +00001245void NetEqDecodingTest::WrapTest(uint16_t start_seq_no,
1246 uint32_t start_timestamp,
1247 const std::set<uint16_t>& drop_seq_numbers,
1248 bool expect_seq_no_wrap,
1249 bool expect_timestamp_wrap) {
1250 uint16_t seq_no = start_seq_no;
1251 uint32_t timestamp = start_timestamp;
1252 const int kBlocksPerFrame = 3; // Number of 10 ms blocks per frame.
1253 const int kFrameSizeMs = kBlocksPerFrame * kTimeStepMs;
1254 const int kSamples = kBlockSize16kHz * kBlocksPerFrame;
1255 const int kPayloadBytes = kSamples * sizeof(int16_t);
1256 double next_input_time_ms = 0.0;
1257 int16_t decoded[kBlockSize16kHz];
1258 int num_channels;
1259 int samples_per_channel;
1260 NetEqOutputType output_type;
1261 uint32_t receive_timestamp = 0;
1262
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +00001263 // Insert speech for 2 seconds.
turaj@webrtc.org78b41a02013-11-22 20:27:07 +00001264 const int kSpeechDurationMs = 2000;
1265 int packets_inserted = 0;
1266 uint16_t last_seq_no;
1267 uint32_t last_timestamp;
1268 bool timestamp_wrapped = false;
1269 bool seq_no_wrapped = false;
1270 for (double t_ms = 0; t_ms < kSpeechDurationMs; t_ms += 10) {
1271 // Each turn in this for loop is 10 ms.
1272 while (next_input_time_ms <= t_ms) {
1273 // Insert one 30 ms speech frame.
1274 uint8_t payload[kPayloadBytes] = {0};
1275 WebRtcRTPHeader rtp_info;
1276 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
1277 if (drop_seq_numbers.find(seq_no) == drop_seq_numbers.end()) {
1278 // This sequence number was not in the set to drop. Insert it.
1279 ASSERT_EQ(0,
1280 neteq_->InsertPacket(rtp_info, payload, kPayloadBytes,
1281 receive_timestamp));
1282 ++packets_inserted;
1283 }
1284 NetEqNetworkStatistics network_stats;
1285 ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats));
1286
1287 // Due to internal NetEq logic, preferred buffer-size is about 4 times the
1288 // packet size for first few packets. Therefore we refrain from checking
1289 // the criteria.
1290 if (packets_inserted > 4) {
1291 // Expect preferred and actual buffer size to be no more than 2 frames.
1292 EXPECT_LE(network_stats.preferred_buffer_size_ms, kFrameSizeMs * 2);
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001293 EXPECT_LE(network_stats.current_buffer_size_ms, kFrameSizeMs * 2 +
1294 algorithmic_delay_ms_);
turaj@webrtc.org78b41a02013-11-22 20:27:07 +00001295 }
1296 last_seq_no = seq_no;
1297 last_timestamp = timestamp;
1298
1299 ++seq_no;
1300 timestamp += kSamples;
1301 receive_timestamp += kSamples;
1302 next_input_time_ms += static_cast<double>(kFrameSizeMs);
1303
1304 seq_no_wrapped |= seq_no < last_seq_no;
1305 timestamp_wrapped |= timestamp < last_timestamp;
1306 }
1307 // Pull out data once.
1308 ASSERT_EQ(0, neteq_->GetAudio(kBlockSize16kHz, decoded,
1309 &samples_per_channel, &num_channels,
1310 &output_type));
1311 ASSERT_EQ(kBlockSize16kHz, samples_per_channel);
1312 ASSERT_EQ(1, num_channels);
1313
1314 // Expect delay (in samples) to be less than 2 packets.
wu@webrtc.org94454b72014-06-05 20:34:08 +00001315 EXPECT_LE(timestamp - PlayoutTimestamp(),
turaj@webrtc.org78b41a02013-11-22 20:27:07 +00001316 static_cast<uint32_t>(kSamples * 2));
turaj@webrtc.org78b41a02013-11-22 20:27:07 +00001317 }
1318 // Make sure we have actually tested wrap-around.
1319 ASSERT_EQ(expect_seq_no_wrap, seq_no_wrapped);
1320 ASSERT_EQ(expect_timestamp_wrap, timestamp_wrapped);
1321}
1322
1323TEST_F(NetEqDecodingTest, SequenceNumberWrap) {
1324 // Start with a sequence number that will soon wrap.
1325 std::set<uint16_t> drop_seq_numbers; // Don't drop any packets.
1326 WrapTest(0xFFFF - 10, 0, drop_seq_numbers, true, false);
1327}
1328
1329TEST_F(NetEqDecodingTest, SequenceNumberWrapAndDrop) {
1330 // Start with a sequence number that will soon wrap.
1331 std::set<uint16_t> drop_seq_numbers;
1332 drop_seq_numbers.insert(0xFFFF);
1333 drop_seq_numbers.insert(0x0);
1334 WrapTest(0xFFFF - 10, 0, drop_seq_numbers, true, false);
1335}
1336
1337TEST_F(NetEqDecodingTest, TimestampWrap) {
1338 // Start with a timestamp that will soon wrap.
1339 std::set<uint16_t> drop_seq_numbers;
1340 WrapTest(0, 0xFFFFFFFF - 3000, drop_seq_numbers, false, true);
1341}
1342
1343TEST_F(NetEqDecodingTest, TimestampAndSequenceNumberWrap) {
1344 // Start with a timestamp and a sequence number that will wrap at the same
1345 // time.
1346 std::set<uint16_t> drop_seq_numbers;
1347 WrapTest(0xFFFF - 10, 0xFFFFFFFF - 5000, drop_seq_numbers, true, true);
1348}
1349
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +00001350void NetEqDecodingTest::DuplicateCng() {
1351 uint16_t seq_no = 0;
1352 uint32_t timestamp = 0;
1353 const int kFrameSizeMs = 10;
1354 const int kSampleRateKhz = 16;
1355 const int kSamples = kFrameSizeMs * kSampleRateKhz;
1356 const int kPayloadBytes = kSamples * 2;
1357
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001358 const int algorithmic_delay_samples = std::max(
1359 algorithmic_delay_ms_ * kSampleRateKhz, 5 * kSampleRateKhz / 8);
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +00001360 // Insert three speech packet. Three are needed to get the frame length
1361 // correct.
1362 int out_len;
1363 int num_channels;
1364 NetEqOutputType type;
1365 uint8_t payload[kPayloadBytes] = {0};
1366 WebRtcRTPHeader rtp_info;
1367 for (int i = 0; i < 3; ++i) {
1368 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
1369 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
1370 ++seq_no;
1371 timestamp += kSamples;
1372
1373 // Pull audio once.
1374 ASSERT_EQ(0,
1375 neteq_->GetAudio(
1376 kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
1377 ASSERT_EQ(kBlockSize16kHz, out_len);
1378 }
1379 // Verify speech output.
1380 EXPECT_EQ(kOutputNormal, type);
1381
1382 // Insert same CNG packet twice.
1383 const int kCngPeriodMs = 100;
1384 const int kCngPeriodSamples = kCngPeriodMs * kSampleRateKhz;
1385 int payload_len;
1386 PopulateCng(seq_no, timestamp, &rtp_info, payload, &payload_len);
1387 // This is the first time this CNG packet is inserted.
1388 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
1389
1390 // Pull audio once and make sure CNG is played.
1391 ASSERT_EQ(0,
1392 neteq_->GetAudio(
1393 kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
1394 ASSERT_EQ(kBlockSize16kHz, out_len);
1395 EXPECT_EQ(kOutputCNG, type);
wu@webrtc.org94454b72014-06-05 20:34:08 +00001396 EXPECT_EQ(timestamp - algorithmic_delay_samples, PlayoutTimestamp());
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +00001397
1398 // Insert the same CNG packet again. Note that at this point it is old, since
1399 // we have already decoded the first copy of it.
1400 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, payload_len, 0));
1401
1402 // Pull audio until we have played |kCngPeriodMs| of CNG. Start at 10 ms since
1403 // we have already pulled out CNG once.
1404 for (int cng_time_ms = 10; cng_time_ms < kCngPeriodMs; cng_time_ms += 10) {
1405 ASSERT_EQ(0,
1406 neteq_->GetAudio(
1407 kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
1408 ASSERT_EQ(kBlockSize16kHz, out_len);
1409 EXPECT_EQ(kOutputCNG, type);
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001410 EXPECT_EQ(timestamp - algorithmic_delay_samples,
wu@webrtc.org94454b72014-06-05 20:34:08 +00001411 PlayoutTimestamp());
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +00001412 }
1413
1414 // Insert speech again.
1415 ++seq_no;
1416 timestamp += kCngPeriodSamples;
1417 PopulateRtpInfo(seq_no, timestamp, &rtp_info);
1418 ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload, kPayloadBytes, 0));
1419
1420 // Pull audio once and verify that the output is speech again.
1421 ASSERT_EQ(0,
1422 neteq_->GetAudio(
1423 kMaxBlockSize, out_data_, &out_len, &num_channels, &type));
1424 ASSERT_EQ(kBlockSize16kHz, out_len);
1425 EXPECT_EQ(kOutputNormal, type);
turaj@webrtc.org8d1cdaa2014-04-11 18:47:55 +00001426 EXPECT_EQ(timestamp + kSamples - algorithmic_delay_samples,
wu@webrtc.org94454b72014-06-05 20:34:08 +00001427 PlayoutTimestamp());
1428}
1429
1430uint32_t NetEqDecodingTest::PlayoutTimestamp() {
1431 uint32_t playout_timestamp = 0;
1432 EXPECT_TRUE(neteq_->GetPlayoutTimestamp(&playout_timestamp));
1433 return playout_timestamp;
henrik.lundin@webrtc.orgca8cb952014-03-12 10:26:52 +00001434}
1435
1436TEST_F(NetEqDecodingTest, DiscardDuplicateCng) { DuplicateCng(); }
henrik.lundin@webrtc.orge7ce4372014-01-09 14:01:55 +00001437} // namespace webrtc