Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_coding / neteq / neteq_stereo_unittest.cc
1 /*
2  *  Copyright (c) 2013 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 // Test to verify correct stereo and multi-channel operation.
12
13 #include <algorithm>
14 #include <string>
15 #include <list>
16
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h"
19 #include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
20 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
21 #include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h"
22 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
23 #include "webrtc/test/testsupport/fileutils.h"
24 #include "webrtc/test/testsupport/gtest_disable.h"
25
26 namespace webrtc {
27
28 struct TestParameters {
29   int frame_size;
30   int sample_rate;
31   int num_channels;
32 };
33
34 // This is a parameterized test. The test parameters are supplied through a
35 // TestParameters struct, which is obtained through the GetParam() method.
36 //
37 // The objective of the test is to create a mono input signal and a
38 // multi-channel input signal, where each channel is identical to the mono
39 // input channel. The two input signals are processed through their respective
40 // NetEq instances. After that, the output signals are compared. The expected
41 // result is that each channel in the multi-channel output is identical to the
42 // mono output.
43 class NetEqStereoTest : public ::testing::TestWithParam<TestParameters> {
44  protected:
45   static const int kTimeStepMs = 10;
46   static const int kMaxBlockSize = 480;  // 10 ms @ 48 kHz.
47   static const uint8_t kPayloadTypeMono = 95;
48   static const uint8_t kPayloadTypeMulti = 96;
49
50   NetEqStereoTest()
51       : num_channels_(GetParam().num_channels),
52         sample_rate_hz_(GetParam().sample_rate),
53         samples_per_ms_(sample_rate_hz_ / 1000),
54         frame_size_ms_(GetParam().frame_size),
55         frame_size_samples_(frame_size_ms_ * samples_per_ms_),
56         output_size_samples_(10 * samples_per_ms_),
57         rtp_generator_mono_(samples_per_ms_),
58         rtp_generator_(samples_per_ms_),
59         payload_size_bytes_(0),
60         multi_payload_size_bytes_(0),
61         last_send_time_(0),
62         last_arrival_time_(0) {
63     NetEq::Config config;
64     config.sample_rate_hz = sample_rate_hz_;
65     neteq_mono_ = NetEq::Create(config);
66     neteq_ = NetEq::Create(config);
67     input_ = new int16_t[frame_size_samples_];
68     encoded_ = new uint8_t[2 * frame_size_samples_];
69     input_multi_channel_ = new int16_t[frame_size_samples_ * num_channels_];
70     encoded_multi_channel_ = new uint8_t[frame_size_samples_ * 2 *
71                                          num_channels_];
72     output_multi_channel_ = new int16_t[kMaxBlockSize * num_channels_];
73   }
74
75   ~NetEqStereoTest() {
76     delete neteq_mono_;
77     delete neteq_;
78     delete [] input_;
79     delete [] encoded_;
80     delete [] input_multi_channel_;
81     delete [] encoded_multi_channel_;
82     delete [] output_multi_channel_;
83   }
84
85   virtual void SetUp() {
86     const std::string file_name =
87         webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
88     input_file_.reset(new test::InputAudioFile(file_name));
89     NetEqDecoder mono_decoder;
90     NetEqDecoder multi_decoder;
91     switch (sample_rate_hz_) {
92       case 8000:
93         mono_decoder = kDecoderPCM16B;
94         if (num_channels_ == 2) {
95           multi_decoder = kDecoderPCM16B_2ch;
96         } else if (num_channels_ == 5) {
97           multi_decoder = kDecoderPCM16B_5ch;
98         } else {
99           FAIL() << "Only 2 and 5 channels supported for 8000 Hz.";
100         }
101         break;
102       case 16000:
103         mono_decoder = kDecoderPCM16Bwb;
104         if (num_channels_ == 2) {
105           multi_decoder = kDecoderPCM16Bwb_2ch;
106         } else {
107           FAIL() << "More than 2 channels is not supported for 16000 Hz.";
108         }
109         break;
110       case 32000:
111         mono_decoder = kDecoderPCM16Bswb32kHz;
112         if (num_channels_ == 2) {
113           multi_decoder = kDecoderPCM16Bswb32kHz_2ch;
114         } else {
115           FAIL() << "More than 2 channels is not supported for 32000 Hz.";
116         }
117         break;
118       case 48000:
119         mono_decoder = kDecoderPCM16Bswb48kHz;
120         if (num_channels_ == 2) {
121           multi_decoder = kDecoderPCM16Bswb48kHz_2ch;
122         } else {
123           FAIL() << "More than 2 channels is not supported for 48000 Hz.";
124         }
125         break;
126       default:
127         FAIL() << "We shouldn't get here.";
128     }
129     ASSERT_EQ(NetEq::kOK,
130               neteq_mono_->RegisterPayloadType(mono_decoder,
131                                                kPayloadTypeMono));
132     ASSERT_EQ(NetEq::kOK,
133               neteq_->RegisterPayloadType(multi_decoder,
134                                           kPayloadTypeMulti));
135   }
136
137   virtual void TearDown() {}
138
139   int GetNewPackets() {
140     if (!input_file_->Read(frame_size_samples_, input_)) {
141       return -1;
142     }
143     payload_size_bytes_ = WebRtcPcm16b_Encode(input_, frame_size_samples_,
144                                              encoded_);
145     if (frame_size_samples_ * 2 != payload_size_bytes_) {
146       return -1;
147     }
148     int next_send_time = rtp_generator_mono_.GetRtpHeader(kPayloadTypeMono,
149                                                           frame_size_samples_,
150                                                           &rtp_header_mono_);
151     test::InputAudioFile::DuplicateInterleaved(input_, frame_size_samples_,
152                                                num_channels_,
153                                                input_multi_channel_);
154     multi_payload_size_bytes_ = WebRtcPcm16b_Encode(
155         input_multi_channel_, frame_size_samples_ * num_channels_,
156         encoded_multi_channel_);
157     if (frame_size_samples_ * 2 * num_channels_ != multi_payload_size_bytes_) {
158       return -1;
159     }
160     rtp_generator_.GetRtpHeader(kPayloadTypeMulti, frame_size_samples_,
161                                 &rtp_header_);
162     return next_send_time;
163   }
164
165   void VerifyOutput(size_t num_samples) {
166     for (size_t i = 0; i < num_samples; ++i) {
167       for (int j = 0; j < num_channels_; ++j) {
168         ASSERT_EQ(output_[i], output_multi_channel_[i * num_channels_ + j]) <<
169             "Diff in sample " << i << ", channel " << j << ".";
170       }
171     }
172   }
173
174   virtual int GetArrivalTime(int send_time) {
175     int arrival_time = last_arrival_time_ + (send_time - last_send_time_);
176     last_send_time_ = send_time;
177     last_arrival_time_ = arrival_time;
178     return arrival_time;
179   }
180
181   virtual bool Lost() { return false; }
182
183   void RunTest(int num_loops) {
184     // Get next input packets (mono and multi-channel).
185     int next_send_time;
186     int next_arrival_time;
187     do {
188       next_send_time = GetNewPackets();
189       ASSERT_NE(-1, next_send_time);
190       next_arrival_time = GetArrivalTime(next_send_time);
191     } while (Lost());  // If lost, immediately read the next packet.
192
193     int time_now = 0;
194     for (int k = 0; k < num_loops; ++k) {
195       while (time_now >= next_arrival_time) {
196         // Insert packet in mono instance.
197         ASSERT_EQ(NetEq::kOK,
198                   neteq_mono_->InsertPacket(rtp_header_mono_, encoded_,
199                                             payload_size_bytes_,
200                                             next_arrival_time));
201         // Insert packet in multi-channel instance.
202         ASSERT_EQ(NetEq::kOK,
203                   neteq_->InsertPacket(rtp_header_, encoded_multi_channel_,
204                                        multi_payload_size_bytes_,
205                                        next_arrival_time));
206         // Get next input packets (mono and multi-channel).
207         do {
208           next_send_time = GetNewPackets();
209           ASSERT_NE(-1, next_send_time);
210           next_arrival_time = GetArrivalTime(next_send_time);
211         } while (Lost());  // If lost, immediately read the next packet.
212       }
213       NetEqOutputType output_type;
214       // Get audio from mono instance.
215       int samples_per_channel;
216       int num_channels;
217       EXPECT_EQ(NetEq::kOK,
218                 neteq_mono_->GetAudio(kMaxBlockSize, output_,
219                                       &samples_per_channel, &num_channels,
220                                       &output_type));
221       EXPECT_EQ(1, num_channels);
222       EXPECT_EQ(output_size_samples_, samples_per_channel);
223       // Get audio from multi-channel instance.
224       ASSERT_EQ(NetEq::kOK,
225                 neteq_->GetAudio(kMaxBlockSize * num_channels_,
226                                  output_multi_channel_,
227                                  &samples_per_channel, &num_channels,
228                                  &output_type));
229       EXPECT_EQ(num_channels_, num_channels);
230       EXPECT_EQ(output_size_samples_, samples_per_channel);
231       std::ostringstream ss;
232       ss << "Lap number " << k << ".";
233       SCOPED_TRACE(ss.str());  // Print out the parameter values on failure.
234       // Compare mono and multi-channel.
235       ASSERT_NO_FATAL_FAILURE(VerifyOutput(output_size_samples_));
236
237       time_now += kTimeStepMs;
238     }
239   }
240
241   const int num_channels_;
242   const int sample_rate_hz_;
243   const int samples_per_ms_;
244   const int frame_size_ms_;
245   const int frame_size_samples_;
246   const int output_size_samples_;
247   NetEq* neteq_mono_;
248   NetEq* neteq_;
249   test::RtpGenerator rtp_generator_mono_;
250   test::RtpGenerator rtp_generator_;
251   int16_t* input_;
252   int16_t* input_multi_channel_;
253   uint8_t* encoded_;
254   uint8_t* encoded_multi_channel_;
255   int16_t output_[kMaxBlockSize];
256   int16_t* output_multi_channel_;
257   WebRtcRTPHeader rtp_header_mono_;
258   WebRtcRTPHeader rtp_header_;
259   int payload_size_bytes_;
260   int multi_payload_size_bytes_;
261   int last_send_time_;
262   int last_arrival_time_;
263   scoped_ptr<test::InputAudioFile> input_file_;
264 };
265
266 class NetEqStereoTestNoJitter : public NetEqStereoTest {
267  protected:
268   NetEqStereoTestNoJitter()
269       : NetEqStereoTest() {
270     // Start the sender 100 ms before the receiver to pre-fill the buffer.
271     // This is to avoid doing preemptive expand early in the test.
272     // TODO(hlundin): Mock the decision making instead to control the modes.
273     last_arrival_time_ = -100;
274   }
275 };
276
277 TEST_P(NetEqStereoTestNoJitter, DISABLED_ON_ANDROID(RunTest)) {
278   RunTest(8);
279 }
280
281 class NetEqStereoTestPositiveDrift : public NetEqStereoTest {
282  protected:
283   NetEqStereoTestPositiveDrift()
284       : NetEqStereoTest(),
285         drift_factor(0.9) {
286     // Start the sender 100 ms before the receiver to pre-fill the buffer.
287     // This is to avoid doing preemptive expand early in the test.
288     // TODO(hlundin): Mock the decision making instead to control the modes.
289     last_arrival_time_ = -100;
290   }
291   virtual int GetArrivalTime(int send_time) {
292     int arrival_time = last_arrival_time_ +
293         drift_factor * (send_time - last_send_time_);
294     last_send_time_ = send_time;
295     last_arrival_time_ = arrival_time;
296     return arrival_time;
297   }
298
299   double drift_factor;
300 };
301
302 TEST_P(NetEqStereoTestPositiveDrift, DISABLED_ON_ANDROID(RunTest)) {
303   RunTest(100);
304 }
305
306 class NetEqStereoTestNegativeDrift : public NetEqStereoTestPositiveDrift {
307  protected:
308   NetEqStereoTestNegativeDrift()
309       : NetEqStereoTestPositiveDrift() {
310     drift_factor = 1.1;
311     last_arrival_time_ = 0;
312   }
313 };
314
315 TEST_P(NetEqStereoTestNegativeDrift, DISABLED_ON_ANDROID(RunTest)) {
316   RunTest(100);
317 }
318
319 class NetEqStereoTestDelays : public NetEqStereoTest {
320  protected:
321   static const int kDelayInterval = 10;
322   static const int kDelay = 1000;
323   NetEqStereoTestDelays()
324       : NetEqStereoTest(),
325         frame_index_(0) {
326   }
327
328   virtual int GetArrivalTime(int send_time) {
329     // Deliver immediately, unless we have a back-log.
330     int arrival_time = std::min(last_arrival_time_, send_time);
331     if (++frame_index_ % kDelayInterval == 0) {
332       // Delay this packet.
333       arrival_time += kDelay;
334     }
335     last_send_time_ = send_time;
336     last_arrival_time_ = arrival_time;
337     return arrival_time;
338   }
339
340   int frame_index_;
341 };
342
343 TEST_P(NetEqStereoTestDelays, DISABLED_ON_ANDROID(RunTest)) {
344   RunTest(1000);
345 }
346
347 class NetEqStereoTestLosses : public NetEqStereoTest {
348  protected:
349   static const int kLossInterval = 10;
350   NetEqStereoTestLosses()
351       : NetEqStereoTest(),
352         frame_index_(0) {
353   }
354
355   virtual bool Lost() {
356     return (++frame_index_) % kLossInterval == 0;
357   }
358
359   int frame_index_;
360 };
361
362 TEST_P(NetEqStereoTestLosses, DISABLED_ON_ANDROID(RunTest)) {
363   RunTest(100);
364 }
365
366
367 // Creates a list of parameter sets.
368 std::list<TestParameters> GetTestParameters() {
369   std::list<TestParameters> l;
370   const int sample_rates[] = {8000, 16000, 32000};
371   const int num_rates = sizeof(sample_rates) / sizeof(sample_rates[0]);
372   // Loop through sample rates.
373   for (int rate_index = 0; rate_index < num_rates; ++rate_index) {
374     int sample_rate = sample_rates[rate_index];
375     // Loop through all frame sizes between 10 and 60 ms.
376     for (int frame_size = 10; frame_size <= 60; frame_size += 10) {
377       TestParameters p;
378       p.frame_size = frame_size;
379       p.sample_rate = sample_rate;
380       p.num_channels = 2;
381       l.push_back(p);
382       if (sample_rate == 8000) {
383         // Add a five-channel test for 8000 Hz.
384         p.num_channels = 5;
385         l.push_back(p);
386       }
387     }
388   }
389   return l;
390 }
391
392 // Pretty-printing the test parameters in case of an error.
393 void PrintTo(const TestParameters& p, ::std::ostream* os) {
394   *os << "{frame_size = " << p.frame_size <<
395       ", num_channels = " << p.num_channels <<
396       ", sample_rate = " << p.sample_rate << "}";
397 }
398
399 // Instantiate the tests. Each test is instantiated using the function above,
400 // so that all different parameter combinations are tested.
401 INSTANTIATE_TEST_CASE_P(MultiChannel,
402                         NetEqStereoTestNoJitter,
403                         ::testing::ValuesIn(GetTestParameters()));
404
405 INSTANTIATE_TEST_CASE_P(MultiChannel,
406                         NetEqStereoTestPositiveDrift,
407                         ::testing::ValuesIn(GetTestParameters()));
408
409 INSTANTIATE_TEST_CASE_P(MultiChannel,
410                         NetEqStereoTestNegativeDrift,
411                         ::testing::ValuesIn(GetTestParameters()));
412
413 INSTANTIATE_TEST_CASE_P(MultiChannel,
414                         NetEqStereoTestDelays,
415                         ::testing::ValuesIn(GetTestParameters()));
416
417 INSTANTIATE_TEST_CASE_P(MultiChannel,
418                         NetEqStereoTestLosses,
419                         ::testing::ValuesIn(GetTestParameters()));
420
421 }  // namespace webrtc