Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: webrtc/modules/audio_coding/main/acm2/audio_coding_module_unittest.cc

Issue 1415163002: Removing AudioCoding class, a.k.a the new ACM API (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2014 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 #include <string.h>
12 #include <vector>
13
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "webrtc/base/checks.h"
16 #include "webrtc/base/md5digest.h"
17 #include "webrtc/base/scoped_ptr.h"
18 #include "webrtc/base/thread_annotations.h"
19 #include "webrtc/modules/audio_coding/main/acm2/acm_receive_test.h"
20 #include "webrtc/modules/audio_coding/main/acm2/acm_send_test.h"
21 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
22 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedef s.h"
23 #include "webrtc/modules/audio_coding/neteq/tools/audio_checksum.h"
24 #include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
25 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
26 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
27 #include "webrtc/modules/audio_coding/neteq/tools/packet.h"
28 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h"
29 #include "webrtc/modules/interface/module_common_types.h"
30 #include "webrtc/system_wrappers/interface/clock.h"
31 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
32 #include "webrtc/system_wrappers/interface/event_wrapper.h"
33 #include "webrtc/system_wrappers/interface/sleep.h"
34 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
35 #include "webrtc/test/testsupport/fileutils.h"
36 #include "webrtc/test/testsupport/gtest_disable.h"
37
38 namespace webrtc {
39
40 const int kSampleRateHz = 16000;
41 const int kNumSamples10ms = kSampleRateHz / 100;
42 const int kFrameSizeMs = 10; // Multiple of 10.
43 const int kFrameSizeSamples = kFrameSizeMs / 10 * kNumSamples10ms;
44 const size_t kPayloadSizeBytes = kFrameSizeSamples * sizeof(int16_t);
45 const uint8_t kPayloadType = 111;
46
47 class RtpUtility {
48 public:
49 RtpUtility(int samples_per_packet, uint8_t payload_type)
50 : samples_per_packet_(samples_per_packet), payload_type_(payload_type) {}
51
52 virtual ~RtpUtility() {}
53
54 void Populate(WebRtcRTPHeader* rtp_header) {
55 rtp_header->header.sequenceNumber = 0xABCD;
56 rtp_header->header.timestamp = 0xABCDEF01;
57 rtp_header->header.payloadType = payload_type_;
58 rtp_header->header.markerBit = false;
59 rtp_header->header.ssrc = 0x1234;
60 rtp_header->header.numCSRCs = 0;
61 rtp_header->frameType = kAudioFrameSpeech;
62
63 rtp_header->header.payload_type_frequency = kSampleRateHz;
64 rtp_header->type.Audio.channel = 1;
65 rtp_header->type.Audio.isCNG = false;
66 }
67
68 void Forward(WebRtcRTPHeader* rtp_header) {
69 ++rtp_header->header.sequenceNumber;
70 rtp_header->header.timestamp += samples_per_packet_;
71 }
72
73 private:
74 int samples_per_packet_;
75 uint8_t payload_type_;
76 };
77
78 class PacketizationCallbackStub : public AudioPacketizationCallback {
79 public:
80 PacketizationCallbackStub()
81 : num_calls_(0),
82 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) {}
83
84 int32_t SendData(FrameType frame_type,
85 uint8_t payload_type,
86 uint32_t timestamp,
87 const uint8_t* payload_data,
88 size_t payload_len_bytes,
89 const RTPFragmentationHeader* fragmentation) override {
90 CriticalSectionScoped lock(crit_sect_.get());
91 ++num_calls_;
92 last_payload_vec_.assign(payload_data, payload_data + payload_len_bytes);
93 return 0;
94 }
95
96 int num_calls() const {
97 CriticalSectionScoped lock(crit_sect_.get());
98 return num_calls_;
99 }
100
101 int last_payload_len_bytes() const {
102 CriticalSectionScoped lock(crit_sect_.get());
103 return last_payload_vec_.size();
104 }
105
106 void SwapBuffers(std::vector<uint8_t>* payload) {
107 CriticalSectionScoped lock(crit_sect_.get());
108 last_payload_vec_.swap(*payload);
109 }
110
111 private:
112 int num_calls_ GUARDED_BY(crit_sect_);
113 std::vector<uint8_t> last_payload_vec_ GUARDED_BY(crit_sect_);
114 const rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_;
115 };
116
117 class AudioCodingModuleTest : public ::testing::Test {
118 protected:
119 AudioCodingModuleTest()
120 : rtp_utility_(new RtpUtility(kFrameSizeSamples, kPayloadType)) {
121 config_.transport = &packet_cb_;
122 }
123
124 ~AudioCodingModuleTest() {}
125
126 void TearDown() override {}
127
128 void SetUp() override {
129 rtp_utility_->Populate(&rtp_header_);
130
131 input_frame_.sample_rate_hz_ = kSampleRateHz;
132 input_frame_.num_channels_ = 1;
133 input_frame_.samples_per_channel_ = kSampleRateHz * 10 / 1000; // 10 ms.
134 static_assert(kSampleRateHz * 10 / 1000 <= AudioFrame::kMaxDataSizeSamples,
135 "audio frame too small");
136 memset(input_frame_.data_,
137 0,
138 input_frame_.samples_per_channel_ * sizeof(input_frame_.data_[0]));
139 }
140
141 void CreateAcm() {
142 acm_.reset(AudioCoding::Create(config_));
143 ASSERT_TRUE(acm_.get() != NULL);
144 RegisterCodec();
145 }
146
147 virtual void RegisterCodec() {
148 // Register L16 codec in ACM.
149 int codec_type = acm2::ACMCodecDB::kNone;
150 switch (kSampleRateHz) {
151 case 8000:
152 codec_type = acm2::ACMCodecDB::kPCM16B;
153 break;
154 case 16000:
155 codec_type = acm2::ACMCodecDB::kPCM16Bwb;
156 break;
157 case 32000:
158 codec_type = acm2::ACMCodecDB::kPCM16Bswb32kHz;
159 break;
160 default:
161 FATAL() << "Sample rate not supported in this test.";
162 }
163 ASSERT_TRUE(acm_->RegisterSendCodec(codec_type, kPayloadType));
164 ASSERT_TRUE(acm_->RegisterReceiveCodec(codec_type, kPayloadType));
165 }
166
167 virtual void InsertPacketAndPullAudio() {
168 InsertPacket();
169 PullAudio();
170 }
171
172 virtual void InsertPacket() {
173 const uint8_t kPayload[kPayloadSizeBytes] = {0};
174 ASSERT_TRUE(acm_->InsertPacket(kPayload, kPayloadSizeBytes, rtp_header_));
175 rtp_utility_->Forward(&rtp_header_);
176 }
177
178 virtual void PullAudio() {
179 AudioFrame audio_frame;
180 ASSERT_TRUE(acm_->Get10MsAudio(&audio_frame));
181 }
182
183 virtual void InsertAudio() {
184 int encoded_bytes = acm_->Add10MsAudio(input_frame_);
185 ASSERT_GE(encoded_bytes, 0);
186 input_frame_.timestamp_ += kNumSamples10ms;
187 }
188
189 AudioCoding::Config config_;
190 rtc::scoped_ptr<RtpUtility> rtp_utility_;
191 rtc::scoped_ptr<AudioCoding> acm_;
192 PacketizationCallbackStub packet_cb_;
193 WebRtcRTPHeader rtp_header_;
194 AudioFrame input_frame_;
195 };
196
197 // Check if the statistics are initialized correctly. Before any call to ACM
198 // all fields have to be zero.
199 TEST_F(AudioCodingModuleTest, DISABLED_ON_ANDROID(InitializedToZero)) {
200 CreateAcm();
201 AudioDecodingCallStats stats;
202 acm_->GetDecodingCallStatistics(&stats);
203 EXPECT_EQ(0, stats.calls_to_neteq);
204 EXPECT_EQ(0, stats.calls_to_silence_generator);
205 EXPECT_EQ(0, stats.decoded_normal);
206 EXPECT_EQ(0, stats.decoded_cng);
207 EXPECT_EQ(0, stats.decoded_plc);
208 EXPECT_EQ(0, stats.decoded_plc_cng);
209 }
210
211 // Apply an initial playout delay. Calls to AudioCodingModule::PlayoutData10ms()
212 // should result in generating silence, check the associated field.
213 TEST_F(AudioCodingModuleTest, DISABLED_ON_ANDROID(SilenceGeneratorCalled)) {
214 const int kInitialDelay = 100;
215 config_.initial_playout_delay_ms = kInitialDelay;
216 CreateAcm();
217 AudioDecodingCallStats stats;
218
219 int num_calls = 0;
220 for (int time_ms = 0; time_ms < kInitialDelay;
221 time_ms += kFrameSizeMs, ++num_calls) {
222 InsertPacketAndPullAudio();
223 }
224 acm_->GetDecodingCallStatistics(&stats);
225 EXPECT_EQ(0, stats.calls_to_neteq);
226 EXPECT_EQ(num_calls, stats.calls_to_silence_generator);
227 EXPECT_EQ(0, stats.decoded_normal);
228 EXPECT_EQ(0, stats.decoded_cng);
229 EXPECT_EQ(0, stats.decoded_plc);
230 EXPECT_EQ(0, stats.decoded_plc_cng);
231 }
232
233 // Insert some packets and pull audio. Check statistics are valid. Then,
234 // simulate packet loss and check if PLC and PLC-to-CNG statistics are
235 // correctly updated.
236 TEST_F(AudioCodingModuleTest, DISABLED_ON_ANDROID(NetEqCalls)) {
237 CreateAcm();
238 AudioDecodingCallStats stats;
239 const int kNumNormalCalls = 10;
240
241 for (int num_calls = 0; num_calls < kNumNormalCalls; ++num_calls) {
242 InsertPacketAndPullAudio();
243 }
244 acm_->GetDecodingCallStatistics(&stats);
245 EXPECT_EQ(kNumNormalCalls, stats.calls_to_neteq);
246 EXPECT_EQ(0, stats.calls_to_silence_generator);
247 EXPECT_EQ(kNumNormalCalls, stats.decoded_normal);
248 EXPECT_EQ(0, stats.decoded_cng);
249 EXPECT_EQ(0, stats.decoded_plc);
250 EXPECT_EQ(0, stats.decoded_plc_cng);
251
252 const int kNumPlc = 3;
253 const int kNumPlcCng = 5;
254
255 // Simulate packet-loss. NetEq first performs PLC then PLC fades to CNG.
256 for (int n = 0; n < kNumPlc + kNumPlcCng; ++n) {
257 PullAudio();
258 }
259 acm_->GetDecodingCallStatistics(&stats);
260 EXPECT_EQ(kNumNormalCalls + kNumPlc + kNumPlcCng, stats.calls_to_neteq);
261 EXPECT_EQ(0, stats.calls_to_silence_generator);
262 EXPECT_EQ(kNumNormalCalls, stats.decoded_normal);
263 EXPECT_EQ(0, stats.decoded_cng);
264 EXPECT_EQ(kNumPlc, stats.decoded_plc);
265 EXPECT_EQ(kNumPlcCng, stats.decoded_plc_cng);
266 }
267
268 TEST_F(AudioCodingModuleTest, VerifyOutputFrame) {
269 CreateAcm();
270 AudioFrame audio_frame;
271 const int kSampleRateHz = 32000;
272 EXPECT_TRUE(acm_->Get10MsAudio(&audio_frame));
273 EXPECT_EQ(0u, audio_frame.timestamp_);
274 EXPECT_GT(audio_frame.num_channels_, 0);
275 EXPECT_EQ(static_cast<size_t>(kSampleRateHz / 100),
276 audio_frame.samples_per_channel_);
277 EXPECT_EQ(kSampleRateHz, audio_frame.sample_rate_hz_);
278 }
279
280 // A multi-threaded test for ACM. This base class is using the PCM16b 16 kHz
281 // codec, while the derive class AcmIsacMtTest is using iSAC.
282 class AudioCodingModuleMtTest : public AudioCodingModuleTest {
283 protected:
284 static const int kNumPackets = 500;
285 static const int kNumPullCalls = 500;
286
287 AudioCodingModuleMtTest()
288 : AudioCodingModuleTest(),
289 send_thread_(ThreadWrapper::CreateThread(CbSendThread, this, "send")),
290 insert_packet_thread_(ThreadWrapper::CreateThread(
291 CbInsertPacketThread, this, "insert_packet")),
292 pull_audio_thread_(ThreadWrapper::CreateThread(
293 CbPullAudioThread, this, "pull_audio")),
294 test_complete_(EventWrapper::Create()),
295 send_count_(0),
296 insert_packet_count_(0),
297 pull_audio_count_(0),
298 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
299 next_insert_packet_time_ms_(0),
300 fake_clock_(new SimulatedClock(0)) {
301 config_.clock = fake_clock_.get();
302 }
303
304 void SetUp() override {
305 AudioCodingModuleTest::SetUp();
306 CreateAcm();
307 StartThreads();
308 }
309
310 void StartThreads() {
311 ASSERT_TRUE(send_thread_->Start());
312 send_thread_->SetPriority(kRealtimePriority);
313 ASSERT_TRUE(insert_packet_thread_->Start());
314 insert_packet_thread_->SetPriority(kRealtimePriority);
315 ASSERT_TRUE(pull_audio_thread_->Start());
316 pull_audio_thread_->SetPriority(kRealtimePriority);
317 }
318
319 void TearDown() override {
320 AudioCodingModuleTest::TearDown();
321 pull_audio_thread_->Stop();
322 send_thread_->Stop();
323 insert_packet_thread_->Stop();
324 }
325
326 EventTypeWrapper RunTest() {
327 return test_complete_->Wait(10 * 60 * 1000); // 10 minutes' timeout.
328 }
329
330 virtual bool TestDone() {
331 if (packet_cb_.num_calls() > kNumPackets) {
332 CriticalSectionScoped lock(crit_sect_.get());
333 if (pull_audio_count_ > kNumPullCalls) {
334 // Both conditions for completion are met. End the test.
335 return true;
336 }
337 }
338 return false;
339 }
340
341 static bool CbSendThread(void* context) {
342 return reinterpret_cast<AudioCodingModuleMtTest*>(context)->CbSendImpl();
343 }
344
345 // The send thread doesn't have to care about the current simulated time,
346 // since only the AcmReceiver is using the clock.
347 bool CbSendImpl() {
348 SleepMs(1);
349 if (HasFatalFailure()) {
350 // End the test early if a fatal failure (ASSERT_*) has occurred.
351 test_complete_->Set();
352 }
353 ++send_count_;
354 InsertAudio();
355 if (TestDone()) {
356 test_complete_->Set();
357 }
358 return true;
359 }
360
361 static bool CbInsertPacketThread(void* context) {
362 return reinterpret_cast<AudioCodingModuleMtTest*>(context)
363 ->CbInsertPacketImpl();
364 }
365
366 bool CbInsertPacketImpl() {
367 SleepMs(1);
368 {
369 CriticalSectionScoped lock(crit_sect_.get());
370 if (fake_clock_->TimeInMilliseconds() < next_insert_packet_time_ms_) {
371 return true;
372 }
373 next_insert_packet_time_ms_ += 10;
374 }
375 // Now we're not holding the crit sect when calling ACM.
376 ++insert_packet_count_;
377 InsertPacket();
378 return true;
379 }
380
381 static bool CbPullAudioThread(void* context) {
382 return reinterpret_cast<AudioCodingModuleMtTest*>(context)
383 ->CbPullAudioImpl();
384 }
385
386 bool CbPullAudioImpl() {
387 SleepMs(1);
388 {
389 CriticalSectionScoped lock(crit_sect_.get());
390 // Don't let the insert thread fall behind.
391 if (next_insert_packet_time_ms_ < fake_clock_->TimeInMilliseconds()) {
392 return true;
393 }
394 ++pull_audio_count_;
395 }
396 // Now we're not holding the crit sect when calling ACM.
397 PullAudio();
398 fake_clock_->AdvanceTimeMilliseconds(10);
399 return true;
400 }
401
402 rtc::scoped_ptr<ThreadWrapper> send_thread_;
403 rtc::scoped_ptr<ThreadWrapper> insert_packet_thread_;
404 rtc::scoped_ptr<ThreadWrapper> pull_audio_thread_;
405 const rtc::scoped_ptr<EventWrapper> test_complete_;
406 int send_count_;
407 int insert_packet_count_;
408 int pull_audio_count_ GUARDED_BY(crit_sect_);
409 const rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_;
410 int64_t next_insert_packet_time_ms_ GUARDED_BY(crit_sect_);
411 rtc::scoped_ptr<SimulatedClock> fake_clock_;
412 };
413
414 TEST_F(AudioCodingModuleMtTest, DoTest) {
415 EXPECT_EQ(kEventSignaled, RunTest());
416 }
417
418 // This is a multi-threaded ACM test using iSAC. The test encodes audio
419 // from a PCM file. The most recent encoded frame is used as input to the
420 // receiving part. Depending on timing, it may happen that the same RTP packet
421 // is inserted into the receiver multiple times, but this is a valid use-case,
422 // and simplifies the test code a lot.
423 class AcmIsacMtTest : public AudioCodingModuleMtTest {
424 protected:
425 static const int kNumPackets = 500;
426 static const int kNumPullCalls = 500;
427
428 AcmIsacMtTest()
429 : AudioCodingModuleMtTest(),
430 last_packet_number_(0) {}
431
432 ~AcmIsacMtTest() {}
433
434 void SetUp() override {
435 AudioCodingModuleTest::SetUp();
436 CreateAcm();
437
438 // Set up input audio source to read from specified file, loop after 5
439 // seconds, and deliver blocks of 10 ms.
440 const std::string input_file_name =
441 webrtc::test::ResourcePath("audio_coding/speech_mono_16kHz", "pcm");
442 audio_loop_.Init(input_file_name, 5 * kSampleRateHz, kNumSamples10ms);
443
444 // Generate one packet to have something to insert.
445 int loop_counter = 0;
446 while (packet_cb_.last_payload_len_bytes() == 0) {
447 InsertAudio();
448 ASSERT_LT(loop_counter++, 10);
449 }
450 // Set |last_packet_number_| to one less that |num_calls| so that the packet
451 // will be fetched in the next InsertPacket() call.
452 last_packet_number_ = packet_cb_.num_calls() - 1;
453
454 StartThreads();
455 }
456
457 void RegisterCodec() override {
458 static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz");
459
460 // Register iSAC codec in ACM, effectively unregistering the PCM16B codec
461 // registered in AudioCodingModuleTest::SetUp();
462 ASSERT_TRUE(acm_->RegisterSendCodec(acm2::ACMCodecDB::kISAC, kPayloadType));
463 ASSERT_TRUE(
464 acm_->RegisterReceiveCodec(acm2::ACMCodecDB::kISAC, kPayloadType));
465 }
466
467 void InsertPacket() override {
468 int num_calls = packet_cb_.num_calls(); // Store locally for thread safety.
469 if (num_calls > last_packet_number_) {
470 // Get the new payload out from the callback handler.
471 // Note that since we swap buffers here instead of directly inserting
472 // a pointer to the data in |packet_cb_|, we avoid locking the callback
473 // for the duration of the IncomingPacket() call.
474 packet_cb_.SwapBuffers(&last_payload_vec_);
475 ASSERT_GT(last_payload_vec_.size(), 0u);
476 rtp_utility_->Forward(&rtp_header_);
477 last_packet_number_ = num_calls;
478 }
479 ASSERT_GT(last_payload_vec_.size(), 0u);
480 ASSERT_TRUE(acm_->InsertPacket(
481 &last_payload_vec_[0], last_payload_vec_.size(), rtp_header_));
482 }
483
484 void InsertAudio() override {
485 memcpy(input_frame_.data_, audio_loop_.GetNextBlock(), kNumSamples10ms);
486 AudioCodingModuleTest::InsertAudio();
487 }
488
489 // This method is the same as AudioCodingModuleMtTest::TestDone(), but here
490 // it is using the constants defined in this class (i.e., shorter test run).
491 bool TestDone() override {
492 if (packet_cb_.num_calls() > kNumPackets) {
493 CriticalSectionScoped lock(crit_sect_.get());
494 if (pull_audio_count_ > kNumPullCalls) {
495 // Both conditions for completion are met. End the test.
496 return true;
497 }
498 }
499 return false;
500 }
501
502 int last_packet_number_;
503 std::vector<uint8_t> last_payload_vec_;
504 test::AudioLoop audio_loop_;
505 };
506
507 #if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
508 #define IF_ISAC(x) x
509 #else
510 #define IF_ISAC(x) DISABLED_##x
511 #endif
512
513 TEST_F(AcmIsacMtTest, IF_ISAC(DoTest)) {
514 EXPECT_EQ(kEventSignaled, RunTest());
515 }
516
517 // Disabling all of these tests on iOS for now.
518 // See https://code.google.com/p/webrtc/issues/detail?id=4768 for details.
519 #if !defined(WEBRTC_IOS)
520
521 class AcmReceiverBitExactness : public ::testing::Test {
522 public:
523 static std::string PlatformChecksum(std::string win64,
524 std::string android,
525 std::string others) {
526 #if defined(_WIN32) && defined(WEBRTC_ARCH_64_BITS)
527 return win64;
528 #elif defined(WEBRTC_ANDROID)
529 return android;
530 #else
531 return others;
532 #endif
533 }
534
535 protected:
536 void Run(int output_freq_hz, const std::string& checksum_ref) {
537 const std::string input_file_name =
538 webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
539 rtc::scoped_ptr<test::RtpFileSource> packet_source(
540 test::RtpFileSource::Create(input_file_name));
541 #ifdef WEBRTC_ANDROID
542 // Filter out iLBC and iSAC-swb since they are not supported on Android.
543 packet_source->FilterOutPayloadType(102); // iLBC.
544 packet_source->FilterOutPayloadType(104); // iSAC-swb.
545 #endif
546
547 test::AudioChecksum checksum;
548 const std::string output_file_name =
549 webrtc::test::OutputPath() +
550 ::testing::UnitTest::GetInstance()
551 ->current_test_info()
552 ->test_case_name() +
553 "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() +
554 "_output.pcm";
555 test::OutputAudioFile output_file(output_file_name);
556 test::AudioSinkFork output(&checksum, &output_file);
557
558 test::AcmReceiveTest test(packet_source.get(), &output, output_freq_hz,
559 test::AcmReceiveTest::kArbitraryChannels);
560 ASSERT_NO_FATAL_FAILURE(test.RegisterNetEqTestCodecs());
561 test.Run();
562
563 std::string checksum_string = checksum.Finish();
564 EXPECT_EQ(checksum_ref, checksum_string);
565 }
566 };
567
568 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISAC)) && \
569 defined(WEBRTC_CODEC_ILBC) && defined(WEBRTC_CODEC_G722)
570 #define IF_ALL_CODECS(x) x
571 #else
572 #define IF_ALL_CODECS(x) DISABLED_##x
573 #endif
574
575 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
576 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
577 #define MAYBE_8kHzOutput DISABLED_8kHzOutput
578 #else
579 #define MAYBE_8kHzOutput 8kHzOutput
580 #endif
581 TEST_F(AcmReceiverBitExactness, IF_ALL_CODECS(MAYBE_8kHzOutput)) {
582 Run(8000,
583 PlatformChecksum("dcee98c623b147ebe1b40dd30efa896e",
584 "adc92e173f908f93b96ba5844209815a",
585 "908002dc01fc4eb1d2be24eb1d3f354b"));
586 }
587
588 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
589 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
590 #define MAYBE_16kHzOutput DISABLED_16kHzOutput
591 #else
592 #define MAYBE_16kHzOutput 16kHzOutput
593 #endif
594 TEST_F(AcmReceiverBitExactness, IF_ALL_CODECS(MAYBE_16kHzOutput)) {
595 Run(16000,
596 PlatformChecksum("f790e7a8cce4e2c8b7bb5e0e4c5dac0d",
597 "8cffa6abcb3e18e33b9d857666dff66a",
598 "a909560b5ca49fa472b17b7b277195e9"));
599 }
600
601 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
602 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
603 #define MAYBE_32kHzOutput DISABLED_32kHzOutput
604 #else
605 #define MAYBE_32kHzOutput 32kHzOutput
606 #endif
607 TEST_F(AcmReceiverBitExactness, IF_ALL_CODECS(MAYBE_32kHzOutput)) {
608 Run(32000,
609 PlatformChecksum("306e0d990ee6e92de3fbecc0123ece37",
610 "3e126fe894720c3f85edadcc91964ba5",
611 "441aab4b347fb3db4e9244337aca8d8e"));
612 }
613
614 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
615 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
616 #define MAYBE_48kHzOutput DISABLED_48kHzOutput
617 #else
618 #define MAYBE_48kHzOutput 48kHzOutput
619 #endif
620 TEST_F(AcmReceiverBitExactness, IF_ALL_CODECS(MAYBE_48kHzOutput)) {
621 Run(48000,
622 PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0",
623 "0155665e93067c4e89256b944dd11999",
624 "4ee2730fa1daae755e8a8fd3abd779ec"));
625 }
626
627 // This test verifies bit exactness for the send-side of ACM. The test setup is
628 // a chain of three different test classes:
629 //
630 // test::AcmSendTest -> AcmSenderBitExactness -> test::AcmReceiveTest
631 //
632 // The receiver side is driving the test by requesting new packets from
633 // AcmSenderBitExactness::NextPacket(). This method, in turn, asks for the
634 // packet from test::AcmSendTest::NextPacket, which inserts audio from the
635 // input file until one packet is produced. (The input file loops indefinitely.)
636 // Before passing the packet to the receiver, this test class verifies the
637 // packet header and updates a payload checksum with the new payload. The
638 // decoded output from the receiver is also verified with a (separate) checksum.
639 class AcmSenderBitExactness : public ::testing::Test,
640 public test::PacketSource {
641 protected:
642 static const int kTestDurationMs = 1000;
643
644 AcmSenderBitExactness()
645 : frame_size_rtp_timestamps_(0),
646 packet_count_(0),
647 payload_type_(0),
648 last_sequence_number_(0),
649 last_timestamp_(0) {}
650
651 // Sets up the test::AcmSendTest object. Returns true on success, otherwise
652 // false.
653 bool SetUpSender() {
654 const std::string input_file_name =
655 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
656 // Note that |audio_source_| will loop forever. The test duration is set
657 // explicitly by |kTestDurationMs|.
658 audio_source_.reset(new test::InputAudioFile(input_file_name));
659 static const int kSourceRateHz = 32000;
660 send_test_.reset(new test::AcmSendTest(
661 audio_source_.get(), kSourceRateHz, kTestDurationMs));
662 return send_test_.get() != NULL;
663 }
664
665 // Registers a send codec in the test::AcmSendTest object. Returns true on
666 // success, false on failure.
667 bool RegisterSendCodec(int codec_type,
668 int channels,
669 int payload_type,
670 int frame_size_samples,
671 int frame_size_rtp_timestamps) {
672 payload_type_ = payload_type;
673 frame_size_rtp_timestamps_ = frame_size_rtp_timestamps;
674 return send_test_->RegisterCodec(
675 codec_type, channels, payload_type, frame_size_samples);
676 }
677
678 // Runs the test. SetUpSender() and RegisterSendCodec() must have been called
679 // before calling this method.
680 void Run(const std::string& audio_checksum_ref,
681 const std::string& payload_checksum_ref,
682 int expected_packets,
683 test::AcmReceiveTest::NumOutputChannels expected_channels) {
684 // Set up the receiver used to decode the packets and verify the decoded
685 // output.
686 test::AudioChecksum audio_checksum;
687 const std::string output_file_name =
688 webrtc::test::OutputPath() +
689 ::testing::UnitTest::GetInstance()
690 ->current_test_info()
691 ->test_case_name() +
692 "_" +
693 ::testing::UnitTest::GetInstance()->current_test_info()->name() +
694 "_output.pcm";
695 test::OutputAudioFile output_file(output_file_name);
696 // Have the output audio sent both to file and to the checksum calculator.
697 test::AudioSinkFork output(&audio_checksum, &output_file);
698 const int kOutputFreqHz = 8000;
699 test::AcmReceiveTest receive_test(
700 this, &output, kOutputFreqHz, expected_channels);
701 ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs());
702
703 // This is where the actual test is executed.
704 receive_test.Run();
705
706 // Extract and verify the audio checksum.
707 std::string checksum_string = audio_checksum.Finish();
708 EXPECT_EQ(audio_checksum_ref, checksum_string);
709
710 // Extract and verify the payload checksum.
711 char checksum_result[rtc::Md5Digest::kSize];
712 payload_checksum_.Finish(checksum_result, rtc::Md5Digest::kSize);
713 checksum_string = rtc::hex_encode(checksum_result, rtc::Md5Digest::kSize);
714 EXPECT_EQ(payload_checksum_ref, checksum_string);
715
716 // Verify number of packets produced.
717 EXPECT_EQ(expected_packets, packet_count_);
718 }
719
720 // Returns a pointer to the next packet. Returns NULL if the source is
721 // depleted (i.e., the test duration is exceeded), or if an error occurred.
722 // Inherited from test::PacketSource.
723 test::Packet* NextPacket() override {
724 // Get the next packet from AcmSendTest. Ownership of |packet| is
725 // transferred to this method.
726 test::Packet* packet = send_test_->NextPacket();
727 if (!packet)
728 return NULL;
729
730 VerifyPacket(packet);
731 // TODO(henrik.lundin) Save the packet to file as well.
732
733 // Pass it on to the caller. The caller becomes the owner of |packet|.
734 return packet;
735 }
736
737 // Verifies the packet.
738 void VerifyPacket(const test::Packet* packet) {
739 EXPECT_TRUE(packet->valid_header());
740 // (We can check the header fields even if valid_header() is false.)
741 EXPECT_EQ(payload_type_, packet->header().payloadType);
742 if (packet_count_ > 0) {
743 // This is not the first packet.
744 uint16_t sequence_number_diff =
745 packet->header().sequenceNumber - last_sequence_number_;
746 EXPECT_EQ(1, sequence_number_diff);
747 uint32_t timestamp_diff = packet->header().timestamp - last_timestamp_;
748 EXPECT_EQ(frame_size_rtp_timestamps_, timestamp_diff);
749 }
750 ++packet_count_;
751 last_sequence_number_ = packet->header().sequenceNumber;
752 last_timestamp_ = packet->header().timestamp;
753 // Update the checksum.
754 payload_checksum_.Update(packet->payload(), packet->payload_length_bytes());
755 }
756
757 void SetUpTest(int codec_type,
758 int channels,
759 int payload_type,
760 int codec_frame_size_samples,
761 int codec_frame_size_rtp_timestamps) {
762 ASSERT_TRUE(SetUpSender());
763 ASSERT_TRUE(RegisterSendCodec(codec_type,
764 channels,
765 payload_type,
766 codec_frame_size_samples,
767 codec_frame_size_rtp_timestamps));
768 }
769
770 rtc::scoped_ptr<test::AcmSendTest> send_test_;
771 rtc::scoped_ptr<test::InputAudioFile> audio_source_;
772 uint32_t frame_size_rtp_timestamps_;
773 int packet_count_;
774 uint8_t payload_type_;
775 uint16_t last_sequence_number_;
776 uint32_t last_timestamp_;
777 rtc::Md5Digest payload_checksum_;
778 };
779
780 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
781 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
782 #define MAYBE_IsacWb30ms DISABLED_IsacWb30ms
783 #else
784 #define MAYBE_IsacWb30ms IsacWb30ms
785 #endif
786 TEST_F(AcmSenderBitExactness, IF_ISAC(MAYBE_IsacWb30ms)) {
787 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kISAC, 1, 103, 480, 480));
788 Run(AcmReceiverBitExactness::PlatformChecksum(
789 "c7e5bdadfa2871df95639fcc297cf23d",
790 "0499ca260390769b3172136faad925b9",
791 "0b58f9eeee43d5891f5f6c75e77984a3"),
792 AcmReceiverBitExactness::PlatformChecksum(
793 "d42cb5195463da26c8129bbfe73a22e6",
794 "83de248aea9c3c2bd680b6952401b4ca",
795 "3c79f16f34218271f3dca4e2b1dfe1bb"),
796 33,
797 test::AcmReceiveTest::kMonoOutput);
798 }
799
800 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
801 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
802 #define MAYBE_IsacWb60ms DISABLED_IsacWb60ms
803 #else
804 #define MAYBE_IsacWb60ms IsacWb60ms
805 #endif
806 TEST_F(AcmSenderBitExactness, IF_ISAC(MAYBE_IsacWb60ms)) {
807 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kISAC, 1, 103, 960, 960));
808 Run(AcmReceiverBitExactness::PlatformChecksum(
809 "14d63c5f08127d280e722e3191b73bdd",
810 "8da003e16c5371af2dc2be79a50f9076",
811 "1ad29139a04782a33daad8c2b9b35875"),
812 AcmReceiverBitExactness::PlatformChecksum(
813 "ebe04a819d3a9d83a83a17f271e1139a",
814 "97aeef98553b5a4b5a68f8b716e8eaf0",
815 "9e0a0ab743ad987b55b8e14802769c56"),
816 16,
817 test::AcmReceiveTest::kMonoOutput);
818 }
819
820 #ifdef WEBRTC_CODEC_ISAC
821 #define IF_ISAC_FLOAT(x) x
822 #else
823 #define IF_ISAC_FLOAT(x) DISABLED_##x
824 #endif
825
826 TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(IF_ISAC_FLOAT(IsacSwb30ms))) {
827 ASSERT_NO_FATAL_FAILURE(
828 SetUpTest(acm2::ACMCodecDB::kISACSWB, 1, 104, 960, 960));
829 Run(AcmReceiverBitExactness::PlatformChecksum(
830 "2b3c387d06f00b7b7aad4c9be56fb83d",
831 "",
832 "5683b58da0fbf2063c7adc2e6bfb3fb8"),
833 AcmReceiverBitExactness::PlatformChecksum(
834 "bcc2041e7744c7ebd9f701866856849c",
835 "",
836 "ce86106a93419aefb063097108ec94ab"),
837 33, test::AcmReceiveTest::kMonoOutput);
838 }
839
840 TEST_F(AcmSenderBitExactness, Pcm16_8000khz_10ms) {
841 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kPCM16B, 1, 107, 80, 80));
842 Run("de4a98e1406f8b798d99cd0704e862e2",
843 "c1edd36339ce0326cc4550041ad719a0",
844 100,
845 test::AcmReceiveTest::kMonoOutput);
846 }
847
848 TEST_F(AcmSenderBitExactness, Pcm16_16000khz_10ms) {
849 ASSERT_NO_FATAL_FAILURE(
850 SetUpTest(acm2::ACMCodecDB::kPCM16Bwb, 1, 108, 160, 160));
851 Run("ae646d7b68384a1269cc080dd4501916",
852 "ad786526383178b08d80d6eee06e9bad",
853 100,
854 test::AcmReceiveTest::kMonoOutput);
855 }
856
857 TEST_F(AcmSenderBitExactness, Pcm16_32000khz_10ms) {
858 ASSERT_NO_FATAL_FAILURE(
859 SetUpTest(acm2::ACMCodecDB::kPCM16Bswb32kHz, 1, 109, 320, 320));
860 Run("7fe325e8fbaf755e3c5df0b11a4774fb",
861 "5ef82ea885e922263606c6fdbc49f651",
862 100,
863 test::AcmReceiveTest::kMonoOutput);
864 }
865
866 TEST_F(AcmSenderBitExactness, Pcm16_stereo_8000khz_10ms) {
867 ASSERT_NO_FATAL_FAILURE(
868 SetUpTest(acm2::ACMCodecDB::kPCM16B_2ch, 2, 111, 80, 80));
869 Run("fb263b74e7ac3de915474d77e4744ceb",
870 "62ce5adb0d4965d0a52ec98ae7f98974",
871 100,
872 test::AcmReceiveTest::kStereoOutput);
873 }
874
875 TEST_F(AcmSenderBitExactness, Pcm16_stereo_16000khz_10ms) {
876 ASSERT_NO_FATAL_FAILURE(
877 SetUpTest(acm2::ACMCodecDB::kPCM16Bwb_2ch, 2, 112, 160, 160));
878 Run("d09e9239553649d7ac93e19d304281fd",
879 "41ca8edac4b8c71cd54fd9f25ec14870",
880 100,
881 test::AcmReceiveTest::kStereoOutput);
882 }
883
884 TEST_F(AcmSenderBitExactness, Pcm16_stereo_32000khz_10ms) {
885 ASSERT_NO_FATAL_FAILURE(
886 SetUpTest(acm2::ACMCodecDB::kPCM16Bswb32kHz_2ch, 2, 113, 320, 320));
887 Run("5f025d4f390982cc26b3d92fe02e3044",
888 "50e58502fb04421bf5b857dda4c96879",
889 100,
890 test::AcmReceiveTest::kStereoOutput);
891 }
892
893 TEST_F(AcmSenderBitExactness, Pcmu_20ms) {
894 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kPCMU, 1, 0, 160, 160));
895 Run("81a9d4c0bb72e9becc43aef124c981e9",
896 "8f9b8750bd80fe26b6cbf6659b89f0f9",
897 50,
898 test::AcmReceiveTest::kMonoOutput);
899 }
900
901 TEST_F(AcmSenderBitExactness, Pcma_20ms) {
902 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kPCMA, 1, 8, 160, 160));
903 Run("39611f798969053925a49dc06d08de29",
904 "6ad745e55aa48981bfc790d0eeef2dd1",
905 50,
906 test::AcmReceiveTest::kMonoOutput);
907 }
908
909 TEST_F(AcmSenderBitExactness, Pcmu_stereo_20ms) {
910 ASSERT_NO_FATAL_FAILURE(
911 SetUpTest(acm2::ACMCodecDB::kPCMU_2ch, 2, 110, 160, 160));
912 Run("437bec032fdc5cbaa0d5175430af7b18",
913 "60b6f25e8d1e74cb679cfe756dd9bca5",
914 50,
915 test::AcmReceiveTest::kStereoOutput);
916 }
917
918 TEST_F(AcmSenderBitExactness, Pcma_stereo_20ms) {
919 ASSERT_NO_FATAL_FAILURE(
920 SetUpTest(acm2::ACMCodecDB::kPCMA_2ch, 2, 118, 160, 160));
921 Run("a5c6d83c5b7cedbeff734238220a4b0c",
922 "92b282c83efd20e7eeef52ba40842cf7",
923 50,
924 test::AcmReceiveTest::kStereoOutput);
925 }
926
927 #ifdef WEBRTC_CODEC_ILBC
928 #define IF_ILBC(x) x
929 #else
930 #define IF_ILBC(x) DISABLED_##x
931 #endif
932
933 TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(IF_ILBC(Ilbc_30ms))) {
934 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kILBC, 1, 102, 240, 240));
935 Run(AcmReceiverBitExactness::PlatformChecksum(
936 "7b6ec10910debd9af08011d3ed5249f7",
937 "android_audio",
938 "7b6ec10910debd9af08011d3ed5249f7"),
939 AcmReceiverBitExactness::PlatformChecksum(
940 "cfae2e9f6aba96e145f2bcdd5050ce78",
941 "android_payload",
942 "cfae2e9f6aba96e145f2bcdd5050ce78"),
943 33,
944 test::AcmReceiveTest::kMonoOutput);
945 }
946
947 #ifdef WEBRTC_CODEC_G722
948 #define IF_G722(x) x
949 #else
950 #define IF_G722(x) DISABLED_##x
951 #endif
952
953 TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(IF_G722(G722_20ms))) {
954 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kG722, 1, 9, 320, 160));
955 Run(AcmReceiverBitExactness::PlatformChecksum(
956 "7d759436f2533582950d148b5161a36c",
957 "android_audio",
958 "7d759436f2533582950d148b5161a36c"),
959 AcmReceiverBitExactness::PlatformChecksum(
960 "fc68a87e1380614e658087cb35d5ca10",
961 "android_payload",
962 "fc68a87e1380614e658087cb35d5ca10"),
963 50,
964 test::AcmReceiveTest::kMonoOutput);
965 }
966
967 TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(IF_G722(G722_stereo_20ms))) {
968 ASSERT_NO_FATAL_FAILURE(
969 SetUpTest(acm2::ACMCodecDB::kG722_2ch, 2, 119, 320, 160));
970 Run(AcmReceiverBitExactness::PlatformChecksum(
971 "7190ee718ab3d80eca181e5f7140c210",
972 "android_audio",
973 "7190ee718ab3d80eca181e5f7140c210"),
974 AcmReceiverBitExactness::PlatformChecksum(
975 "66516152eeaa1e650ad94ff85f668dac",
976 "android_payload",
977 "66516152eeaa1e650ad94ff85f668dac"),
978 50,
979 test::AcmReceiveTest::kStereoOutput);
980 }
981
982 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199
983 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64)
984 #define MAYBE_Opus_stereo_20ms DISABLED_Opus_stereo_20ms
985 #else
986 #define MAYBE_Opus_stereo_20ms Opus_stereo_20ms
987 #endif
988 TEST_F(AcmSenderBitExactness, MAYBE_Opus_stereo_20ms) {
989 ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kOpus, 2, 120, 960, 960));
990 Run(AcmReceiverBitExactness::PlatformChecksum(
991 "855041f2490b887302bce9d544731849",
992 "1e1a0fce893fef2d66886a7f09e2ebce",
993 "855041f2490b887302bce9d544731849"),
994 AcmReceiverBitExactness::PlatformChecksum(
995 "d781cce1ab986b618d0da87226cdde30",
996 "1a1fe04dd12e755949987c8d729fb3e0",
997 "d781cce1ab986b618d0da87226cdde30"),
998 50,
999 test::AcmReceiveTest::kStereoOutput);
1000 }
1001
1002 #endif
1003
1004 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698