OLD | NEW |
| (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 | |
OLD | NEW |