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