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 operation for externally created decoders.
12
13#include <string>
14#include <list>
15
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18#include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
19#include "webrtc/modules/audio_coding/neteq/mock/mock_external_decoder_pcm16b.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/compile_assert.h"
23#include "webrtc/system_wrappers/interface/scoped_ptr.h"
24#include "webrtc/test/testsupport/fileutils.h"
25#include "webrtc/test/testsupport/gtest_disable.h"
26
27namespace webrtc {
28
29using ::testing::_;
30using ::testing::Return;
31
32// This test encodes a few packets of PCM16b 32 kHz data and inserts it into two
33// different NetEq instances. The first instance uses the internal version of
34// the decoder object, while the second one uses an externally created decoder
35// object (ExternalPcm16B wrapped in MockExternalPcm16B, both defined above).
36// The test verifies that the output from both instances match.
37class NetEqExternalDecoderTest : public ::testing::Test {
38 protected:
39  static const int kTimeStepMs = 10;
40  static const int kMaxBlockSize = 480;  // 10 ms @ 48 kHz.
41  static const uint8_t kPayloadType = 95;
42  static const int kSampleRateHz = 32000;
43
44  NetEqExternalDecoderTest()
45      : sample_rate_hz_(kSampleRateHz),
46        samples_per_ms_(sample_rate_hz_ / 1000),
47        frame_size_ms_(10),
48        frame_size_samples_(frame_size_ms_ * samples_per_ms_),
49        output_size_samples_(frame_size_ms_ * samples_per_ms_),
50        external_decoder_(new MockExternalPcm16B(kDecoderPCM16Bswb32kHz)),
51        rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
52        payload_size_bytes_(0),
53        last_send_time_(0),
54        last_arrival_time_(0) {
55    config_.sample_rate_hz = sample_rate_hz_;
56    neteq_external_ = NetEq::Create(config_);
57    neteq_ = NetEq::Create(config_);
58    input_ = new int16_t[frame_size_samples_];
59    encoded_ = new uint8_t[2 * frame_size_samples_];
60  }
61
62  ~NetEqExternalDecoderTest() {
63    delete neteq_external_;
64    delete neteq_;
65    // We will now delete the decoder ourselves, so expecting Die to be called.
66    EXPECT_CALL(*external_decoder_, Die()).Times(1);
67    delete [] input_;
68    delete [] encoded_;
69  }
70
71  virtual void SetUp() {
72    const std::string file_name =
73        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
74    input_file_.reset(new test::InputAudioFile(file_name));
75    assert(sample_rate_hz_ == 32000);
76    NetEqDecoder decoder = kDecoderPCM16Bswb32kHz;
77    EXPECT_CALL(*external_decoder_, Init());
78    // NetEq is not allowed to delete the external decoder (hence Times(0)).
79    EXPECT_CALL(*external_decoder_, Die()).Times(0);
80    ASSERT_EQ(NetEq::kOK,
81              neteq_external_->RegisterExternalDecoder(
82                  external_decoder_.get(), decoder, kPayloadType));
83    ASSERT_EQ(NetEq::kOK,
84              neteq_->RegisterPayloadType(decoder, kPayloadType));
85  }
86
87  virtual void TearDown() {}
88
89  int GetNewPackets() {
90    if (!input_file_->Read(frame_size_samples_, input_)) {
91      return -1;
92    }
93    payload_size_bytes_ = WebRtcPcm16b_Encode(input_, frame_size_samples_,
94                                             encoded_);
95    if (frame_size_samples_ * 2 != payload_size_bytes_) {
96      return -1;
97    }
98    int next_send_time = rtp_generator_->GetRtpHeader(
99        kPayloadType, frame_size_samples_, &rtp_header_);
100    return next_send_time;
101  }
102
103  virtual void VerifyOutput(size_t num_samples) const {
104    for (size_t i = 0; i < num_samples; ++i) {
105      ASSERT_EQ(output_[i], output_external_[i]) <<
106          "Diff in sample " << i << ".";
107    }
108  }
109
110  virtual int GetArrivalTime(int send_time) {
111    int arrival_time = last_arrival_time_ + (send_time - last_send_time_);
112    last_send_time_ = send_time;
113    last_arrival_time_ = arrival_time;
114    return arrival_time;
115  }
116
117  virtual bool Lost() { return false; }
118
119  virtual void InsertPackets(int next_arrival_time) {
120    // Insert packet in regular instance.
121    ASSERT_EQ(
122        NetEq::kOK,
123        neteq_->InsertPacket(
124            rtp_header_, encoded_, payload_size_bytes_, next_arrival_time));
125    // Insert packet in external decoder instance.
126    EXPECT_CALL(*external_decoder_,
127                IncomingPacket(_,
128                               payload_size_bytes_,
129                               rtp_header_.header.sequenceNumber,
130                               rtp_header_.header.timestamp,
131                               next_arrival_time));
132    ASSERT_EQ(
133        NetEq::kOK,
134        neteq_external_->InsertPacket(
135            rtp_header_, encoded_, payload_size_bytes_, next_arrival_time));
136  }
137
138  virtual void GetOutputAudio() {
139    NetEqOutputType output_type;
140    // Get audio from regular instance.
141    int samples_per_channel;
142    int num_channels;
143    EXPECT_EQ(NetEq::kOK,
144              neteq_->GetAudio(kMaxBlockSize,
145                               output_,
146                               &samples_per_channel,
147                               &num_channels,
148                               &output_type));
149    EXPECT_EQ(1, num_channels);
150    EXPECT_EQ(output_size_samples_, samples_per_channel);
151    // Get audio from external decoder instance.
152    ASSERT_EQ(NetEq::kOK,
153              neteq_external_->GetAudio(kMaxBlockSize,
154                                        output_external_,
155                                        &samples_per_channel,
156                                        &num_channels,
157                                        &output_type));
158    EXPECT_EQ(1, num_channels);
159    EXPECT_EQ(output_size_samples_, samples_per_channel);
160  }
161
162  virtual int NumExpectedDecodeCalls(int num_loops) const { return num_loops; }
163
164  void RunTest(int num_loops) {
165    // Get next input packets (mono and multi-channel).
166    int next_send_time;
167    int next_arrival_time;
168    do {
169      next_send_time = GetNewPackets();
170      ASSERT_NE(-1, next_send_time);
171      next_arrival_time = GetArrivalTime(next_send_time);
172    } while (Lost());  // If lost, immediately read the next packet.
173
174    EXPECT_CALL(*external_decoder_, Decode(_, payload_size_bytes_, _, _))
175        .Times(NumExpectedDecodeCalls(num_loops));
176
177    int time_now = 0;
178    for (int k = 0; k < num_loops; ++k) {
179      while (time_now >= next_arrival_time) {
180        InsertPackets(next_arrival_time);
181
182        // Get next input packet.
183        do {
184          next_send_time = GetNewPackets();
185          ASSERT_NE(-1, next_send_time);
186          next_arrival_time = GetArrivalTime(next_send_time);
187        } while (Lost());  // If lost, immediately read the next packet.
188      }
189
190      GetOutputAudio();
191
192      std::ostringstream ss;
193      ss << "Lap number " << k << ".";
194      SCOPED_TRACE(ss.str());  // Print out the parameter values on failure.
195      // Compare mono and multi-channel.
196      ASSERT_NO_FATAL_FAILURE(VerifyOutput(output_size_samples_));
197
198      time_now += kTimeStepMs;
199    }
200  }
201
202  NetEq::Config config_;
203  int sample_rate_hz_;
204  int samples_per_ms_;
205  const int frame_size_ms_;
206  int frame_size_samples_;
207  int output_size_samples_;
208  NetEq* neteq_external_;
209  NetEq* neteq_;
210  scoped_ptr<MockExternalPcm16B> external_decoder_;
211  scoped_ptr<test::RtpGenerator> rtp_generator_;
212  int16_t* input_;
213  uint8_t* encoded_;
214  int16_t output_[kMaxBlockSize];
215  int16_t output_external_[kMaxBlockSize];
216  WebRtcRTPHeader rtp_header_;
217  int payload_size_bytes_;
218  int last_send_time_;
219  int last_arrival_time_;
220  scoped_ptr<test::InputAudioFile> input_file_;
221};
222
223TEST_F(NetEqExternalDecoderTest, RunTest) {
224  RunTest(100);  // Run 100 laps @ 10 ms each in the test loop.
225}
226
227class LargeTimestampJumpTest : public NetEqExternalDecoderTest {
228 protected:
229  enum TestStates {
230    kInitialPhase,
231    kNormalPhase,
232    kExpandPhase,
233    kFadedExpandPhase,
234    kRecovered
235  };
236
237  LargeTimestampJumpTest()
238      : NetEqExternalDecoderTest(), test_state_(kInitialPhase) {
239    sample_rate_hz_ = 8000;
240    samples_per_ms_ = sample_rate_hz_ / 1000;
241    frame_size_samples_ = frame_size_ms_ * samples_per_ms_;
242    output_size_samples_ = frame_size_ms_ * samples_per_ms_;
243    EXPECT_CALL(*external_decoder_, Die()).Times(1);
244    external_decoder_.reset(new MockExternalPcm16B(kDecoderPCM16B));
245  }
246
247  void SetUp() OVERRIDE {
248    const std::string file_name =
249        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
250    input_file_.reset(new test::InputAudioFile(file_name));
251    assert(sample_rate_hz_ == 8000);
252    NetEqDecoder decoder = kDecoderPCM16B;
253    EXPECT_CALL(*external_decoder_, Init());
254    EXPECT_CALL(*external_decoder_, HasDecodePlc())
255        .WillRepeatedly(Return(false));
256    // NetEq is not allowed to delete the external decoder (hence Times(0)).
257    EXPECT_CALL(*external_decoder_, Die()).Times(0);
258    ASSERT_EQ(NetEq::kOK,
259              neteq_external_->RegisterExternalDecoder(
260                  external_decoder_.get(), decoder, kPayloadType));
261    ASSERT_EQ(NetEq::kOK, neteq_->RegisterPayloadType(decoder, kPayloadType));
262  }
263
264  void InsertPackets(int next_arrival_time) OVERRIDE {
265    // Insert packet in external decoder instance.
266    EXPECT_CALL(*external_decoder_,
267                IncomingPacket(_,
268                               payload_size_bytes_,
269                               rtp_header_.header.sequenceNumber,
270                               rtp_header_.header.timestamp,
271                               next_arrival_time));
272    ASSERT_EQ(
273        NetEq::kOK,
274        neteq_external_->InsertPacket(
275            rtp_header_, encoded_, payload_size_bytes_, next_arrival_time));
276  }
277
278  void GetOutputAudio() OVERRIDE {
279    NetEqOutputType output_type;
280    int samples_per_channel;
281    int num_channels;
282    // Get audio from external decoder instance.
283    ASSERT_EQ(NetEq::kOK,
284              neteq_external_->GetAudio(kMaxBlockSize,
285                                        output_external_,
286                                        &samples_per_channel,
287                                        &num_channels,
288                                        &output_type));
289    EXPECT_EQ(1, num_channels);
290    EXPECT_EQ(output_size_samples_, samples_per_channel);
291    UpdateState(output_type);
292  }
293
294  virtual void UpdateState(NetEqOutputType output_type) {
295    switch (test_state_) {
296      case kInitialPhase: {
297        if (output_type == kOutputNormal) {
298          test_state_ = kNormalPhase;
299        }
300        break;
301      }
302      case kNormalPhase: {
303        if (output_type == kOutputPLC) {
304          test_state_ = kExpandPhase;
305        }
306        break;
307      }
308      case kExpandPhase: {
309        if (output_type == kOutputPLCtoCNG) {
310          test_state_ = kFadedExpandPhase;
311        }
312        break;
313      }
314      case kFadedExpandPhase: {
315        if (output_type == kOutputNormal) {
316          test_state_ = kRecovered;
317        }
318        break;
319      }
320      case kRecovered: {
321        break;
322      }
323    }
324  }
325
326  void VerifyOutput(size_t num_samples) const OVERRIDE {
327    if (test_state_ == kExpandPhase || test_state_ == kFadedExpandPhase) {
328      // Don't verify the output in this phase of the test.
329      return;
330    }
331    for (size_t i = 0; i < num_samples; ++i) {
332      if (output_external_[i] != 0)
333        return;
334    }
335    EXPECT_TRUE(false)
336        << "Expected at least one non-zero sample in each output block.";
337  }
338
339  int NumExpectedDecodeCalls(int num_loops) const OVERRIDE {
340    // Some packets won't be decoded because of the buffer being flushed after
341    // the timestamp jump.
342    return num_loops - (config_.max_packets_in_buffer + 1);
343  }
344
345  TestStates test_state_;
346};
347
348TEST_F(LargeTimestampJumpTest, JumpLongerThanHalfRange) {
349  // Set the timestamp series to start at 2880, increase to 7200, then jump to
350  // 2869342376. The sequence numbers start at 42076 and increase by 1 for each
351  // packet, also when the timestamp jumps.
352  static const uint16_t kStartSeqeunceNumber = 42076;
353  static const uint32_t kStartTimestamp = 2880;
354  static const uint32_t kJumpFromTimestamp = 7200;
355  static const uint32_t kJumpToTimestamp = 2869342376;
356  COMPILE_ASSERT(kJumpFromTimestamp < kJumpToTimestamp,
357                 timestamp_jump_should_not_result_in_wrap);
358  COMPILE_ASSERT(
359      static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) > 0x7FFFFFFF,
360      jump_should_be_larger_than_half_range);
361  // Replace the default RTP generator with one that jumps in timestamp.
362  rtp_generator_.reset(new test::TimestampJumpRtpGenerator(samples_per_ms_,
363                                                           kStartSeqeunceNumber,
364                                                           kStartTimestamp,
365                                                           kJumpFromTimestamp,
366                                                           kJumpToTimestamp));
367
368  RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
369  EXPECT_EQ(kRecovered, test_state_);
370}
371
372TEST_F(LargeTimestampJumpTest, JumpLongerThanHalfRangeAndWrap) {
373  // Make a jump larger than half the 32-bit timestamp range. Set the start
374  // timestamp such that the jump will result in a wrap around.
375  static const uint16_t kStartSeqeunceNumber = 42076;
376  // Set the jump length slightly larger than 2^31.
377  static const uint32_t kStartTimestamp = 3221223116;
378  static const uint32_t kJumpFromTimestamp = 3221223216;
379  static const uint32_t kJumpToTimestamp = 1073744278;
380  COMPILE_ASSERT(kJumpToTimestamp < kJumpFromTimestamp,
381                 timestamp_jump_should_result_in_wrap);
382  COMPILE_ASSERT(
383      static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) > 0x7FFFFFFF,
384      jump_should_be_larger_than_half_range);
385  // Replace the default RTP generator with one that jumps in timestamp.
386  rtp_generator_.reset(new test::TimestampJumpRtpGenerator(samples_per_ms_,
387                                                           kStartSeqeunceNumber,
388                                                           kStartTimestamp,
389                                                           kJumpFromTimestamp,
390                                                           kJumpToTimestamp));
391
392  RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
393  EXPECT_EQ(kRecovered, test_state_);
394}
395
396class ShortTimestampJumpTest : public LargeTimestampJumpTest {
397 protected:
398  void UpdateState(NetEqOutputType output_type) OVERRIDE {
399    switch (test_state_) {
400      case kInitialPhase: {
401        if (output_type == kOutputNormal) {
402          test_state_ = kNormalPhase;
403        }
404        break;
405      }
406      case kNormalPhase: {
407        if (output_type == kOutputPLC) {
408          test_state_ = kExpandPhase;
409        }
410        break;
411      }
412      case kExpandPhase: {
413        if (output_type == kOutputNormal) {
414          test_state_ = kRecovered;
415        }
416        break;
417      }
418      case kRecovered: {
419        break;
420      }
421      default: { FAIL(); }
422    }
423  }
424
425  int NumExpectedDecodeCalls(int num_loops) const OVERRIDE {
426    // Some packets won't be decoded because of the timestamp jump.
427    return num_loops - 2;
428  }
429};
430
431TEST_F(ShortTimestampJumpTest, JumpShorterThanHalfRange) {
432  // Make a jump shorter than half the 32-bit timestamp range. Set the start
433  // timestamp such that the jump will not result in a wrap around.
434  static const uint16_t kStartSeqeunceNumber = 42076;
435  // Set the jump length slightly smaller than 2^31.
436  static const uint32_t kStartTimestamp = 4711;
437  static const uint32_t kJumpFromTimestamp = 4811;
438  static const uint32_t kJumpToTimestamp = 2147483747;
439  COMPILE_ASSERT(kJumpFromTimestamp < kJumpToTimestamp,
440                 timestamp_jump_should_not_result_in_wrap);
441  COMPILE_ASSERT(
442      static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) < 0x7FFFFFFF,
443      jump_should_be_smaller_than_half_range);
444  // Replace the default RTP generator with one that jumps in timestamp.
445  rtp_generator_.reset(new test::TimestampJumpRtpGenerator(samples_per_ms_,
446                                                           kStartSeqeunceNumber,
447                                                           kStartTimestamp,
448                                                           kJumpFromTimestamp,
449                                                           kJumpToTimestamp));
450
451  RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
452  EXPECT_EQ(kRecovered, test_state_);
453}
454
455TEST_F(ShortTimestampJumpTest, JumpShorterThanHalfRangeAndWrap) {
456  // Make a jump shorter than half the 32-bit timestamp range. Set the start
457  // timestamp such that the jump will result in a wrap around.
458  static const uint16_t kStartSeqeunceNumber = 42076;
459  // Set the jump length slightly smaller than 2^31.
460  static const uint32_t kStartTimestamp = 3221227827;
461  static const uint32_t kJumpFromTimestamp = 3221227927;
462  static const uint32_t kJumpToTimestamp = 1073739567;
463  COMPILE_ASSERT(kJumpToTimestamp < kJumpFromTimestamp,
464                 timestamp_jump_should_result_in_wrap);
465  COMPILE_ASSERT(
466      static_cast<uint32_t>(kJumpToTimestamp - kJumpFromTimestamp) < 0x7FFFFFFF,
467      jump_should_be_smaller_than_half_range);
468  // Replace the default RTP generator with one that jumps in timestamp.
469  rtp_generator_.reset(new test::TimestampJumpRtpGenerator(samples_per_ms_,
470                                                           kStartSeqeunceNumber,
471                                                           kStartTimestamp,
472                                                           kJumpFromTimestamp,
473                                                           kJumpToTimestamp));
474
475  RunTest(130);  // Run 130 laps @ 10 ms each in the test loop.
476  EXPECT_EQ(kRecovered, test_state_);
477}
478
479}  // namespace webrtc
480