Home | History | Annotate | Download | only in neteq
      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 
     27 namespace webrtc {
     28 
     29 using ::testing::_;
     30 using ::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.
     37 class 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 
    223 TEST_F(NetEqExternalDecoderTest, RunTest) {
    224   RunTest(100);  // Run 100 laps @ 10 ms each in the test loop.
    225 }
    226 
    227 class 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 
    348 TEST_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 
    372 TEST_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 
    396 class 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 
    431 TEST_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 
    455 TEST_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