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
NetEqExternalDecoderTest()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
~NetEqExternalDecoderTest()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
SetUp()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
TearDown()87 virtual void TearDown() {}
88
GetNewPackets()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
VerifyOutput(size_t num_samples) const103 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
GetArrivalTime(int send_time)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
Lost()117 virtual bool Lost() { return false; }
118
InsertPackets(int next_arrival_time)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
GetOutputAudio()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
NumExpectedDecodeCalls(int num_loops) const162 virtual int NumExpectedDecodeCalls(int num_loops) const { return num_loops; }
163
RunTest(int num_loops)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
TEST_F(NetEqExternalDecoderTest,RunTest)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
LargeTimestampJumpTest()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
SetUp()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
InsertPackets(int next_arrival_time)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
GetOutputAudio()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
UpdateState(NetEqOutputType output_type)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
VerifyOutput(size_t num_samples) const326 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
NumExpectedDecodeCalls(int num_loops) const339 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
TEST_F(LargeTimestampJumpTest,JumpLongerThanHalfRange)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
TEST_F(LargeTimestampJumpTest,JumpLongerThanHalfRangeAndWrap)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:
UpdateState(NetEqOutputType output_type)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
NumExpectedDecodeCalls(int num_loops) const425 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
TEST_F(ShortTimestampJumpTest,JumpShorterThanHalfRange)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
TEST_F(ShortTimestampJumpTest,JumpShorterThanHalfRangeAndWrap)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