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/md5digest.h" | |
16 #include "webrtc/base/platform_thread.h" | |
17 #include "webrtc/base/scoped_ptr.h" | |
18 #include "webrtc/base/thread_annotations.h" | |
19 #include "webrtc/modules/audio_coding/codecs/audio_encoder.h" | |
20 #include "webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h" | |
21 #include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h" | |
22 #include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isa
c.h" | |
23 #include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h" | |
24 #include "webrtc/modules/audio_coding/main/acm2/acm_receive_test_oldapi.h" | |
25 #include "webrtc/modules/audio_coding/main/acm2/acm_send_test_oldapi.h" | |
26 #include "webrtc/modules/audio_coding/main/include/audio_coding_module.h" | |
27 #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs.
h" | |
28 #include "webrtc/modules/audio_coding/neteq/audio_decoder_impl.h" | |
29 #include "webrtc/modules/audio_coding/neteq/mock/mock_audio_decoder.h" | |
30 #include "webrtc/modules/audio_coding/neteq/tools/audio_checksum.h" | |
31 #include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h" | |
32 #include "webrtc/modules/audio_coding/neteq/tools/constant_pcm_packet_source.h" | |
33 #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" | |
34 #include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h" | |
35 #include "webrtc/modules/audio_coding/neteq/tools/packet.h" | |
36 #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" | |
37 #include "webrtc/modules/include/module_common_types.h" | |
38 #include "webrtc/system_wrappers/include/clock.h" | |
39 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
40 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
41 #include "webrtc/system_wrappers/include/sleep.h" | |
42 #include "webrtc/test/testsupport/fileutils.h" | |
43 #include "webrtc/test/testsupport/gtest_disable.h" | |
44 | |
45 using ::testing::AtLeast; | |
46 using ::testing::Invoke; | |
47 using ::testing::_; | |
48 | |
49 namespace webrtc { | |
50 | |
51 namespace { | |
52 const int kSampleRateHz = 16000; | |
53 const int kNumSamples10ms = kSampleRateHz / 100; | |
54 const int kFrameSizeMs = 10; // Multiple of 10. | |
55 const int kFrameSizeSamples = kFrameSizeMs / 10 * kNumSamples10ms; | |
56 const int kPayloadSizeBytes = kFrameSizeSamples * sizeof(int16_t); | |
57 const uint8_t kPayloadType = 111; | |
58 } // namespace | |
59 | |
60 class RtpUtility { | |
61 public: | |
62 RtpUtility(int samples_per_packet, uint8_t payload_type) | |
63 : samples_per_packet_(samples_per_packet), payload_type_(payload_type) {} | |
64 | |
65 virtual ~RtpUtility() {} | |
66 | |
67 void Populate(WebRtcRTPHeader* rtp_header) { | |
68 rtp_header->header.sequenceNumber = 0xABCD; | |
69 rtp_header->header.timestamp = 0xABCDEF01; | |
70 rtp_header->header.payloadType = payload_type_; | |
71 rtp_header->header.markerBit = false; | |
72 rtp_header->header.ssrc = 0x1234; | |
73 rtp_header->header.numCSRCs = 0; | |
74 rtp_header->frameType = kAudioFrameSpeech; | |
75 | |
76 rtp_header->header.payload_type_frequency = kSampleRateHz; | |
77 rtp_header->type.Audio.channel = 1; | |
78 rtp_header->type.Audio.isCNG = false; | |
79 } | |
80 | |
81 void Forward(WebRtcRTPHeader* rtp_header) { | |
82 ++rtp_header->header.sequenceNumber; | |
83 rtp_header->header.timestamp += samples_per_packet_; | |
84 } | |
85 | |
86 private: | |
87 int samples_per_packet_; | |
88 uint8_t payload_type_; | |
89 }; | |
90 | |
91 class PacketizationCallbackStubOldApi : public AudioPacketizationCallback { | |
92 public: | |
93 PacketizationCallbackStubOldApi() | |
94 : num_calls_(0), | |
95 last_frame_type_(kEmptyFrame), | |
96 last_payload_type_(-1), | |
97 last_timestamp_(0), | |
98 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) {} | |
99 | |
100 int32_t SendData(FrameType frame_type, | |
101 uint8_t payload_type, | |
102 uint32_t timestamp, | |
103 const uint8_t* payload_data, | |
104 size_t payload_len_bytes, | |
105 const RTPFragmentationHeader* fragmentation) override { | |
106 CriticalSectionScoped lock(crit_sect_.get()); | |
107 ++num_calls_; | |
108 last_frame_type_ = frame_type; | |
109 last_payload_type_ = payload_type; | |
110 last_timestamp_ = timestamp; | |
111 last_payload_vec_.assign(payload_data, payload_data + payload_len_bytes); | |
112 return 0; | |
113 } | |
114 | |
115 int num_calls() const { | |
116 CriticalSectionScoped lock(crit_sect_.get()); | |
117 return num_calls_; | |
118 } | |
119 | |
120 int last_payload_len_bytes() const { | |
121 CriticalSectionScoped lock(crit_sect_.get()); | |
122 return last_payload_vec_.size(); | |
123 } | |
124 | |
125 FrameType last_frame_type() const { | |
126 CriticalSectionScoped lock(crit_sect_.get()); | |
127 return last_frame_type_; | |
128 } | |
129 | |
130 int last_payload_type() const { | |
131 CriticalSectionScoped lock(crit_sect_.get()); | |
132 return last_payload_type_; | |
133 } | |
134 | |
135 uint32_t last_timestamp() const { | |
136 CriticalSectionScoped lock(crit_sect_.get()); | |
137 return last_timestamp_; | |
138 } | |
139 | |
140 void SwapBuffers(std::vector<uint8_t>* payload) { | |
141 CriticalSectionScoped lock(crit_sect_.get()); | |
142 last_payload_vec_.swap(*payload); | |
143 } | |
144 | |
145 private: | |
146 int num_calls_ GUARDED_BY(crit_sect_); | |
147 FrameType last_frame_type_ GUARDED_BY(crit_sect_); | |
148 int last_payload_type_ GUARDED_BY(crit_sect_); | |
149 uint32_t last_timestamp_ GUARDED_BY(crit_sect_); | |
150 std::vector<uint8_t> last_payload_vec_ GUARDED_BY(crit_sect_); | |
151 const rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_; | |
152 }; | |
153 | |
154 class AudioCodingModuleTestOldApi : public ::testing::Test { | |
155 protected: | |
156 AudioCodingModuleTestOldApi() | |
157 : id_(1), | |
158 rtp_utility_(new RtpUtility(kFrameSizeSamples, kPayloadType)), | |
159 clock_(Clock::GetRealTimeClock()) {} | |
160 | |
161 ~AudioCodingModuleTestOldApi() {} | |
162 | |
163 void TearDown() {} | |
164 | |
165 void SetUp() { | |
166 acm_.reset(AudioCodingModule::Create(id_, clock_)); | |
167 | |
168 rtp_utility_->Populate(&rtp_header_); | |
169 | |
170 input_frame_.sample_rate_hz_ = kSampleRateHz; | |
171 input_frame_.num_channels_ = 1; | |
172 input_frame_.samples_per_channel_ = kSampleRateHz * 10 / 1000; // 10 ms. | |
173 static_assert(kSampleRateHz * 10 / 1000 <= AudioFrame::kMaxDataSizeSamples, | |
174 "audio frame too small"); | |
175 memset(input_frame_.data_, | |
176 0, | |
177 input_frame_.samples_per_channel_ * sizeof(input_frame_.data_[0])); | |
178 | |
179 ASSERT_EQ(0, acm_->RegisterTransportCallback(&packet_cb_)); | |
180 | |
181 SetUpL16Codec(); | |
182 } | |
183 | |
184 // Set up L16 codec. | |
185 virtual void SetUpL16Codec() { | |
186 ASSERT_EQ(0, AudioCodingModule::Codec("L16", &codec_, kSampleRateHz, 1)); | |
187 codec_.pltype = kPayloadType; | |
188 } | |
189 | |
190 virtual void RegisterCodec() { | |
191 ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec_)); | |
192 ASSERT_EQ(0, acm_->RegisterSendCodec(codec_)); | |
193 } | |
194 | |
195 virtual void InsertPacketAndPullAudio() { | |
196 InsertPacket(); | |
197 PullAudio(); | |
198 } | |
199 | |
200 virtual void InsertPacket() { | |
201 const uint8_t kPayload[kPayloadSizeBytes] = {0}; | |
202 ASSERT_EQ(0, | |
203 acm_->IncomingPacket(kPayload, kPayloadSizeBytes, rtp_header_)); | |
204 rtp_utility_->Forward(&rtp_header_); | |
205 } | |
206 | |
207 virtual void PullAudio() { | |
208 AudioFrame audio_frame; | |
209 ASSERT_EQ(0, acm_->PlayoutData10Ms(-1, &audio_frame)); | |
210 } | |
211 | |
212 virtual void InsertAudio() { | |
213 ASSERT_GE(acm_->Add10MsData(input_frame_), 0); | |
214 input_frame_.timestamp_ += kNumSamples10ms; | |
215 } | |
216 | |
217 virtual void VerifyEncoding() { | |
218 int last_length = packet_cb_.last_payload_len_bytes(); | |
219 EXPECT_TRUE(last_length == 2 * codec_.pacsize || last_length == 0) | |
220 << "Last encoded packet was " << last_length << " bytes."; | |
221 } | |
222 | |
223 virtual void InsertAudioAndVerifyEncoding() { | |
224 InsertAudio(); | |
225 VerifyEncoding(); | |
226 } | |
227 | |
228 const int id_; | |
229 rtc::scoped_ptr<RtpUtility> rtp_utility_; | |
230 rtc::scoped_ptr<AudioCodingModule> acm_; | |
231 PacketizationCallbackStubOldApi packet_cb_; | |
232 WebRtcRTPHeader rtp_header_; | |
233 AudioFrame input_frame_; | |
234 CodecInst codec_; | |
235 Clock* clock_; | |
236 }; | |
237 | |
238 // Check if the statistics are initialized correctly. Before any call to ACM | |
239 // all fields have to be zero. | |
240 TEST_F(AudioCodingModuleTestOldApi, DISABLED_ON_ANDROID(InitializedToZero)) { | |
241 RegisterCodec(); | |
242 AudioDecodingCallStats stats; | |
243 acm_->GetDecodingCallStatistics(&stats); | |
244 EXPECT_EQ(0, stats.calls_to_neteq); | |
245 EXPECT_EQ(0, stats.calls_to_silence_generator); | |
246 EXPECT_EQ(0, stats.decoded_normal); | |
247 EXPECT_EQ(0, stats.decoded_cng); | |
248 EXPECT_EQ(0, stats.decoded_plc); | |
249 EXPECT_EQ(0, stats.decoded_plc_cng); | |
250 } | |
251 | |
252 // Insert some packets and pull audio. Check statistics are valid. Then, | |
253 // simulate packet loss and check if PLC and PLC-to-CNG statistics are | |
254 // correctly updated. | |
255 TEST_F(AudioCodingModuleTestOldApi, DISABLED_ON_ANDROID(NetEqCalls)) { | |
256 RegisterCodec(); | |
257 AudioDecodingCallStats stats; | |
258 const int kNumNormalCalls = 10; | |
259 | |
260 for (int num_calls = 0; num_calls < kNumNormalCalls; ++num_calls) { | |
261 InsertPacketAndPullAudio(); | |
262 } | |
263 acm_->GetDecodingCallStatistics(&stats); | |
264 EXPECT_EQ(kNumNormalCalls, stats.calls_to_neteq); | |
265 EXPECT_EQ(0, stats.calls_to_silence_generator); | |
266 EXPECT_EQ(kNumNormalCalls, stats.decoded_normal); | |
267 EXPECT_EQ(0, stats.decoded_cng); | |
268 EXPECT_EQ(0, stats.decoded_plc); | |
269 EXPECT_EQ(0, stats.decoded_plc_cng); | |
270 | |
271 const int kNumPlc = 3; | |
272 const int kNumPlcCng = 5; | |
273 | |
274 // Simulate packet-loss. NetEq first performs PLC then PLC fades to CNG. | |
275 for (int n = 0; n < kNumPlc + kNumPlcCng; ++n) { | |
276 PullAudio(); | |
277 } | |
278 acm_->GetDecodingCallStatistics(&stats); | |
279 EXPECT_EQ(kNumNormalCalls + kNumPlc + kNumPlcCng, stats.calls_to_neteq); | |
280 EXPECT_EQ(0, stats.calls_to_silence_generator); | |
281 EXPECT_EQ(kNumNormalCalls, stats.decoded_normal); | |
282 EXPECT_EQ(0, stats.decoded_cng); | |
283 EXPECT_EQ(kNumPlc, stats.decoded_plc); | |
284 EXPECT_EQ(kNumPlcCng, stats.decoded_plc_cng); | |
285 } | |
286 | |
287 TEST_F(AudioCodingModuleTestOldApi, VerifyOutputFrame) { | |
288 AudioFrame audio_frame; | |
289 const int kSampleRateHz = 32000; | |
290 EXPECT_EQ(0, acm_->PlayoutData10Ms(kSampleRateHz, &audio_frame)); | |
291 EXPECT_EQ(id_, audio_frame.id_); | |
292 EXPECT_EQ(0u, audio_frame.timestamp_); | |
293 EXPECT_GT(audio_frame.num_channels_, 0); | |
294 EXPECT_EQ(static_cast<size_t>(kSampleRateHz / 100), | |
295 audio_frame.samples_per_channel_); | |
296 EXPECT_EQ(kSampleRateHz, audio_frame.sample_rate_hz_); | |
297 } | |
298 | |
299 TEST_F(AudioCodingModuleTestOldApi, FailOnZeroDesiredFrequency) { | |
300 AudioFrame audio_frame; | |
301 EXPECT_EQ(-1, acm_->PlayoutData10Ms(0, &audio_frame)); | |
302 } | |
303 | |
304 // Checks that the transport callback is invoked once for each speech packet. | |
305 // Also checks that the frame type is kAudioFrameSpeech. | |
306 TEST_F(AudioCodingModuleTestOldApi, TransportCallbackIsInvokedForEachPacket) { | |
307 const int k10MsBlocksPerPacket = 3; | |
308 codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100; | |
309 RegisterCodec(); | |
310 const int kLoops = 10; | |
311 for (int i = 0; i < kLoops; ++i) { | |
312 EXPECT_EQ(i / k10MsBlocksPerPacket, packet_cb_.num_calls()); | |
313 if (packet_cb_.num_calls() > 0) | |
314 EXPECT_EQ(kAudioFrameSpeech, packet_cb_.last_frame_type()); | |
315 InsertAudioAndVerifyEncoding(); | |
316 } | |
317 EXPECT_EQ(kLoops / k10MsBlocksPerPacket, packet_cb_.num_calls()); | |
318 EXPECT_EQ(kAudioFrameSpeech, packet_cb_.last_frame_type()); | |
319 } | |
320 | |
321 #if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX) | |
322 #define IF_ISAC(x) x | |
323 #else | |
324 #define IF_ISAC(x) DISABLED_##x | |
325 #endif | |
326 | |
327 // Verifies that the RTP timestamp series is not reset when the codec is | |
328 // changed. | |
329 TEST_F(AudioCodingModuleTestOldApi, | |
330 IF_ISAC(TimestampSeriesContinuesWhenCodecChanges)) { | |
331 RegisterCodec(); // This registers the default codec. | |
332 uint32_t expected_ts = input_frame_.timestamp_; | |
333 int blocks_per_packet = codec_.pacsize / (kSampleRateHz / 100); | |
334 // Encode 5 packets of the first codec type. | |
335 const int kNumPackets1 = 5; | |
336 for (int j = 0; j < kNumPackets1; ++j) { | |
337 for (int i = 0; i < blocks_per_packet; ++i) { | |
338 EXPECT_EQ(j, packet_cb_.num_calls()); | |
339 InsertAudio(); | |
340 } | |
341 EXPECT_EQ(j + 1, packet_cb_.num_calls()); | |
342 EXPECT_EQ(expected_ts, packet_cb_.last_timestamp()); | |
343 expected_ts += codec_.pacsize; | |
344 } | |
345 | |
346 // Change codec. | |
347 ASSERT_EQ(0, AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1)); | |
348 RegisterCodec(); | |
349 blocks_per_packet = codec_.pacsize / (kSampleRateHz / 100); | |
350 // Encode another 5 packets. | |
351 const int kNumPackets2 = 5; | |
352 for (int j = 0; j < kNumPackets2; ++j) { | |
353 for (int i = 0; i < blocks_per_packet; ++i) { | |
354 EXPECT_EQ(kNumPackets1 + j, packet_cb_.num_calls()); | |
355 InsertAudio(); | |
356 } | |
357 EXPECT_EQ(kNumPackets1 + j + 1, packet_cb_.num_calls()); | |
358 EXPECT_EQ(expected_ts, packet_cb_.last_timestamp()); | |
359 expected_ts += codec_.pacsize; | |
360 } | |
361 } | |
362 | |
363 // Introduce this class to set different expectations on the number of encoded | |
364 // bytes. This class expects all encoded packets to be 9 bytes (matching one | |
365 // CNG SID frame) or 0 bytes. This test depends on |input_frame_| containing | |
366 // (near-)zero values. It also introduces a way to register comfort noise with | |
367 // a custom payload type. | |
368 class AudioCodingModuleTestWithComfortNoiseOldApi | |
369 : public AudioCodingModuleTestOldApi { | |
370 protected: | |
371 void RegisterCngCodec(int rtp_payload_type) { | |
372 CodecInst codec; | |
373 AudioCodingModule::Codec("CN", &codec, kSampleRateHz, 1); | |
374 codec.pltype = rtp_payload_type; | |
375 ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec)); | |
376 ASSERT_EQ(0, acm_->RegisterSendCodec(codec)); | |
377 } | |
378 | |
379 void VerifyEncoding() override { | |
380 int last_length = packet_cb_.last_payload_len_bytes(); | |
381 EXPECT_TRUE(last_length == 9 || last_length == 0) | |
382 << "Last encoded packet was " << last_length << " bytes."; | |
383 } | |
384 | |
385 void DoTest(int blocks_per_packet, int cng_pt) { | |
386 const int kLoops = 40; | |
387 // This array defines the expected frame types, and when they should arrive. | |
388 // We expect a frame to arrive each time the speech encoder would have | |
389 // produced a packet, and once every 100 ms the frame should be non-empty, | |
390 // that is contain comfort noise. | |
391 const struct { | |
392 int ix; | |
393 FrameType type; | |
394 } expectation[] = {{2, kAudioFrameCN}, | |
395 {5, kEmptyFrame}, | |
396 {8, kEmptyFrame}, | |
397 {11, kAudioFrameCN}, | |
398 {14, kEmptyFrame}, | |
399 {17, kEmptyFrame}, | |
400 {20, kAudioFrameCN}, | |
401 {23, kEmptyFrame}, | |
402 {26, kEmptyFrame}, | |
403 {29, kEmptyFrame}, | |
404 {32, kAudioFrameCN}, | |
405 {35, kEmptyFrame}, | |
406 {38, kEmptyFrame}}; | |
407 for (int i = 0; i < kLoops; ++i) { | |
408 int num_calls_before = packet_cb_.num_calls(); | |
409 EXPECT_EQ(i / blocks_per_packet, num_calls_before); | |
410 InsertAudioAndVerifyEncoding(); | |
411 int num_calls = packet_cb_.num_calls(); | |
412 if (num_calls == num_calls_before + 1) { | |
413 EXPECT_EQ(expectation[num_calls - 1].ix, i); | |
414 EXPECT_EQ(expectation[num_calls - 1].type, packet_cb_.last_frame_type()) | |
415 << "Wrong frame type for lap " << i; | |
416 EXPECT_EQ(cng_pt, packet_cb_.last_payload_type()); | |
417 } else { | |
418 EXPECT_EQ(num_calls, num_calls_before); | |
419 } | |
420 } | |
421 } | |
422 }; | |
423 | |
424 // Checks that the transport callback is invoked once per frame period of the | |
425 // underlying speech encoder, even when comfort noise is produced. | |
426 // Also checks that the frame type is kAudioFrameCN or kEmptyFrame. | |
427 // This test and the next check the same thing, but differ in the order of | |
428 // speech codec and CNG registration. | |
429 TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi, | |
430 TransportCallbackTestForComfortNoiseRegisterCngLast) { | |
431 const int k10MsBlocksPerPacket = 3; | |
432 codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100; | |
433 RegisterCodec(); | |
434 const int kCngPayloadType = 105; | |
435 RegisterCngCodec(kCngPayloadType); | |
436 ASSERT_EQ(0, acm_->SetVAD(true, true)); | |
437 DoTest(k10MsBlocksPerPacket, kCngPayloadType); | |
438 } | |
439 | |
440 TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi, | |
441 TransportCallbackTestForComfortNoiseRegisterCngFirst) { | |
442 const int k10MsBlocksPerPacket = 3; | |
443 codec_.pacsize = k10MsBlocksPerPacket * kSampleRateHz / 100; | |
444 const int kCngPayloadType = 105; | |
445 RegisterCngCodec(kCngPayloadType); | |
446 RegisterCodec(); | |
447 ASSERT_EQ(0, acm_->SetVAD(true, true)); | |
448 DoTest(k10MsBlocksPerPacket, kCngPayloadType); | |
449 } | |
450 | |
451 // A multi-threaded test for ACM. This base class is using the PCM16b 16 kHz | |
452 // codec, while the derive class AcmIsacMtTest is using iSAC. | |
453 class AudioCodingModuleMtTestOldApi : public AudioCodingModuleTestOldApi { | |
454 protected: | |
455 static const int kNumPackets = 500; | |
456 static const int kNumPullCalls = 500; | |
457 | |
458 AudioCodingModuleMtTestOldApi() | |
459 : AudioCodingModuleTestOldApi(), | |
460 send_thread_(PlatformThread::CreateThread(CbSendThread, this, "send")), | |
461 insert_packet_thread_(PlatformThread::CreateThread(CbInsertPacketThread, | |
462 this, | |
463 "insert_packet")), | |
464 pull_audio_thread_(PlatformThread::CreateThread(CbPullAudioThread, | |
465 this, | |
466 "pull_audio")), | |
467 test_complete_(EventWrapper::Create()), | |
468 send_count_(0), | |
469 insert_packet_count_(0), | |
470 pull_audio_count_(0), | |
471 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | |
472 next_insert_packet_time_ms_(0), | |
473 fake_clock_(new SimulatedClock(0)) { | |
474 clock_ = fake_clock_.get(); | |
475 } | |
476 | |
477 void SetUp() { | |
478 AudioCodingModuleTestOldApi::SetUp(); | |
479 RegisterCodec(); // Must be called before the threads start below. | |
480 StartThreads(); | |
481 } | |
482 | |
483 void StartThreads() { | |
484 ASSERT_TRUE(send_thread_->Start()); | |
485 send_thread_->SetPriority(kRealtimePriority); | |
486 ASSERT_TRUE(insert_packet_thread_->Start()); | |
487 insert_packet_thread_->SetPriority(kRealtimePriority); | |
488 ASSERT_TRUE(pull_audio_thread_->Start()); | |
489 pull_audio_thread_->SetPriority(kRealtimePriority); | |
490 } | |
491 | |
492 void TearDown() { | |
493 AudioCodingModuleTestOldApi::TearDown(); | |
494 pull_audio_thread_->Stop(); | |
495 send_thread_->Stop(); | |
496 insert_packet_thread_->Stop(); | |
497 } | |
498 | |
499 EventTypeWrapper RunTest() { | |
500 return test_complete_->Wait(10 * 60 * 1000); // 10 minutes' timeout. | |
501 } | |
502 | |
503 virtual bool TestDone() { | |
504 if (packet_cb_.num_calls() > kNumPackets) { | |
505 CriticalSectionScoped lock(crit_sect_.get()); | |
506 if (pull_audio_count_ > kNumPullCalls) { | |
507 // Both conditions for completion are met. End the test. | |
508 return true; | |
509 } | |
510 } | |
511 return false; | |
512 } | |
513 | |
514 static bool CbSendThread(void* context) { | |
515 return reinterpret_cast<AudioCodingModuleMtTestOldApi*>(context) | |
516 ->CbSendImpl(); | |
517 } | |
518 | |
519 // The send thread doesn't have to care about the current simulated time, | |
520 // since only the AcmReceiver is using the clock. | |
521 bool CbSendImpl() { | |
522 SleepMs(1); | |
523 if (HasFatalFailure()) { | |
524 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
525 test_complete_->Set(); | |
526 } | |
527 ++send_count_; | |
528 InsertAudioAndVerifyEncoding(); | |
529 if (TestDone()) { | |
530 test_complete_->Set(); | |
531 } | |
532 return true; | |
533 } | |
534 | |
535 static bool CbInsertPacketThread(void* context) { | |
536 return reinterpret_cast<AudioCodingModuleMtTestOldApi*>(context) | |
537 ->CbInsertPacketImpl(); | |
538 } | |
539 | |
540 bool CbInsertPacketImpl() { | |
541 SleepMs(1); | |
542 { | |
543 CriticalSectionScoped lock(crit_sect_.get()); | |
544 if (clock_->TimeInMilliseconds() < next_insert_packet_time_ms_) { | |
545 return true; | |
546 } | |
547 next_insert_packet_time_ms_ += 10; | |
548 } | |
549 // Now we're not holding the crit sect when calling ACM. | |
550 ++insert_packet_count_; | |
551 InsertPacket(); | |
552 return true; | |
553 } | |
554 | |
555 static bool CbPullAudioThread(void* context) { | |
556 return reinterpret_cast<AudioCodingModuleMtTestOldApi*>(context) | |
557 ->CbPullAudioImpl(); | |
558 } | |
559 | |
560 bool CbPullAudioImpl() { | |
561 SleepMs(1); | |
562 { | |
563 CriticalSectionScoped lock(crit_sect_.get()); | |
564 // Don't let the insert thread fall behind. | |
565 if (next_insert_packet_time_ms_ < clock_->TimeInMilliseconds()) { | |
566 return true; | |
567 } | |
568 ++pull_audio_count_; | |
569 } | |
570 // Now we're not holding the crit sect when calling ACM. | |
571 PullAudio(); | |
572 fake_clock_->AdvanceTimeMilliseconds(10); | |
573 return true; | |
574 } | |
575 | |
576 rtc::scoped_ptr<PlatformThread> send_thread_; | |
577 rtc::scoped_ptr<PlatformThread> insert_packet_thread_; | |
578 rtc::scoped_ptr<PlatformThread> pull_audio_thread_; | |
579 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
580 int send_count_; | |
581 int insert_packet_count_; | |
582 int pull_audio_count_ GUARDED_BY(crit_sect_); | |
583 const rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_; | |
584 int64_t next_insert_packet_time_ms_ GUARDED_BY(crit_sect_); | |
585 rtc::scoped_ptr<SimulatedClock> fake_clock_; | |
586 }; | |
587 | |
588 TEST_F(AudioCodingModuleMtTestOldApi, DISABLED_ON_IOS(DoTest)) { | |
589 EXPECT_EQ(kEventSignaled, RunTest()); | |
590 } | |
591 | |
592 // This is a multi-threaded ACM test using iSAC. The test encodes audio | |
593 // from a PCM file. The most recent encoded frame is used as input to the | |
594 // receiving part. Depending on timing, it may happen that the same RTP packet | |
595 // is inserted into the receiver multiple times, but this is a valid use-case, | |
596 // and simplifies the test code a lot. | |
597 class AcmIsacMtTestOldApi : public AudioCodingModuleMtTestOldApi { | |
598 protected: | |
599 static const int kNumPackets = 500; | |
600 static const int kNumPullCalls = 500; | |
601 | |
602 AcmIsacMtTestOldApi() | |
603 : AudioCodingModuleMtTestOldApi(), last_packet_number_(0) {} | |
604 | |
605 ~AcmIsacMtTestOldApi() {} | |
606 | |
607 void SetUp() { | |
608 AudioCodingModuleTestOldApi::SetUp(); | |
609 RegisterCodec(); // Must be called before the threads start below. | |
610 | |
611 // Set up input audio source to read from specified file, loop after 5 | |
612 // seconds, and deliver blocks of 10 ms. | |
613 const std::string input_file_name = | |
614 webrtc::test::ResourcePath("audio_coding/speech_mono_16kHz", "pcm"); | |
615 audio_loop_.Init(input_file_name, 5 * kSampleRateHz, kNumSamples10ms); | |
616 | |
617 // Generate one packet to have something to insert. | |
618 int loop_counter = 0; | |
619 while (packet_cb_.last_payload_len_bytes() == 0) { | |
620 InsertAudio(); | |
621 ASSERT_LT(loop_counter++, 10); | |
622 } | |
623 // Set |last_packet_number_| to one less that |num_calls| so that the packet | |
624 // will be fetched in the next InsertPacket() call. | |
625 last_packet_number_ = packet_cb_.num_calls() - 1; | |
626 | |
627 StartThreads(); | |
628 } | |
629 | |
630 void RegisterCodec() override { | |
631 static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz"); | |
632 AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1); | |
633 codec_.pltype = kPayloadType; | |
634 | |
635 // Register iSAC codec in ACM, effectively unregistering the PCM16B codec | |
636 // registered in AudioCodingModuleTestOldApi::SetUp(); | |
637 ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec_)); | |
638 ASSERT_EQ(0, acm_->RegisterSendCodec(codec_)); | |
639 } | |
640 | |
641 void InsertPacket() { | |
642 int num_calls = packet_cb_.num_calls(); // Store locally for thread safety. | |
643 if (num_calls > last_packet_number_) { | |
644 // Get the new payload out from the callback handler. | |
645 // Note that since we swap buffers here instead of directly inserting | |
646 // a pointer to the data in |packet_cb_|, we avoid locking the callback | |
647 // for the duration of the IncomingPacket() call. | |
648 packet_cb_.SwapBuffers(&last_payload_vec_); | |
649 ASSERT_GT(last_payload_vec_.size(), 0u); | |
650 rtp_utility_->Forward(&rtp_header_); | |
651 last_packet_number_ = num_calls; | |
652 } | |
653 ASSERT_GT(last_payload_vec_.size(), 0u); | |
654 ASSERT_EQ( | |
655 0, | |
656 acm_->IncomingPacket( | |
657 &last_payload_vec_[0], last_payload_vec_.size(), rtp_header_)); | |
658 } | |
659 | |
660 void InsertAudio() { | |
661 // TODO(kwiberg): Use std::copy here. Might be complications because AFAICS | |
662 // this call confuses the number of samples with the number of bytes, and | |
663 // ends up copying only half of what it should. | |
664 memcpy(input_frame_.data_, audio_loop_.GetNextBlock().data(), | |
665 kNumSamples10ms); | |
666 AudioCodingModuleTestOldApi::InsertAudio(); | |
667 } | |
668 | |
669 // Override the verification function with no-op, since iSAC produces variable | |
670 // payload sizes. | |
671 void VerifyEncoding() override {} | |
672 | |
673 // This method is the same as AudioCodingModuleMtTestOldApi::TestDone(), but | |
674 // here it is using the constants defined in this class (i.e., shorter test | |
675 // run). | |
676 virtual bool TestDone() { | |
677 if (packet_cb_.num_calls() > kNumPackets) { | |
678 CriticalSectionScoped lock(crit_sect_.get()); | |
679 if (pull_audio_count_ > kNumPullCalls) { | |
680 // Both conditions for completion are met. End the test. | |
681 return true; | |
682 } | |
683 } | |
684 return false; | |
685 } | |
686 | |
687 int last_packet_number_; | |
688 std::vector<uint8_t> last_payload_vec_; | |
689 test::AudioLoop audio_loop_; | |
690 }; | |
691 | |
692 TEST_F(AcmIsacMtTestOldApi, DISABLED_ON_IOS(IF_ISAC(DoTest))) { | |
693 EXPECT_EQ(kEventSignaled, RunTest()); | |
694 } | |
695 | |
696 class AcmReRegisterIsacMtTestOldApi : public AudioCodingModuleTestOldApi { | |
697 protected: | |
698 static const int kRegisterAfterNumPackets = 5; | |
699 static const int kNumPackets = 10; | |
700 static const int kPacketSizeMs = 30; | |
701 static const int kPacketSizeSamples = kPacketSizeMs * 16; | |
702 | |
703 AcmReRegisterIsacMtTestOldApi() | |
704 : AudioCodingModuleTestOldApi(), | |
705 receive_thread_( | |
706 PlatformThread::CreateThread(CbReceiveThread, this, "receive")), | |
707 codec_registration_thread_( | |
708 PlatformThread::CreateThread(CbCodecRegistrationThread, | |
709 this, | |
710 "codec_registration")), | |
711 test_complete_(EventWrapper::Create()), | |
712 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | |
713 codec_registered_(false), | |
714 receive_packet_count_(0), | |
715 next_insert_packet_time_ms_(0), | |
716 fake_clock_(new SimulatedClock(0)) { | |
717 AudioEncoderIsac::Config config; | |
718 config.payload_type = kPayloadType; | |
719 isac_encoder_.reset(new AudioEncoderIsac(config)); | |
720 clock_ = fake_clock_.get(); | |
721 } | |
722 | |
723 void SetUp() { | |
724 AudioCodingModuleTestOldApi::SetUp(); | |
725 // Set up input audio source to read from specified file, loop after 5 | |
726 // seconds, and deliver blocks of 10 ms. | |
727 const std::string input_file_name = | |
728 webrtc::test::ResourcePath("audio_coding/speech_mono_16kHz", "pcm"); | |
729 audio_loop_.Init(input_file_name, 5 * kSampleRateHz, kNumSamples10ms); | |
730 RegisterCodec(); // Must be called before the threads start below. | |
731 StartThreads(); | |
732 } | |
733 | |
734 void RegisterCodec() override { | |
735 static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz"); | |
736 AudioCodingModule::Codec("ISAC", &codec_, kSampleRateHz, 1); | |
737 codec_.pltype = kPayloadType; | |
738 | |
739 // Register iSAC codec in ACM, effectively unregistering the PCM16B codec | |
740 // registered in AudioCodingModuleTestOldApi::SetUp(); | |
741 // Only register the decoder for now. The encoder is registered later. | |
742 ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec_)); | |
743 } | |
744 | |
745 void StartThreads() { | |
746 ASSERT_TRUE(receive_thread_->Start()); | |
747 receive_thread_->SetPriority(kRealtimePriority); | |
748 ASSERT_TRUE(codec_registration_thread_->Start()); | |
749 codec_registration_thread_->SetPriority(kRealtimePriority); | |
750 } | |
751 | |
752 void TearDown() { | |
753 AudioCodingModuleTestOldApi::TearDown(); | |
754 receive_thread_->Stop(); | |
755 codec_registration_thread_->Stop(); | |
756 } | |
757 | |
758 EventTypeWrapper RunTest() { | |
759 return test_complete_->Wait(10 * 60 * 1000); // 10 minutes' timeout. | |
760 } | |
761 | |
762 static bool CbReceiveThread(void* context) { | |
763 return reinterpret_cast<AcmReRegisterIsacMtTestOldApi*>(context) | |
764 ->CbReceiveImpl(); | |
765 } | |
766 | |
767 bool CbReceiveImpl() { | |
768 SleepMs(1); | |
769 const size_t max_encoded_bytes = isac_encoder_->MaxEncodedBytes(); | |
770 rtc::scoped_ptr<uint8_t[]> encoded(new uint8_t[max_encoded_bytes]); | |
771 AudioEncoder::EncodedInfo info; | |
772 { | |
773 CriticalSectionScoped lock(crit_sect_.get()); | |
774 if (clock_->TimeInMilliseconds() < next_insert_packet_time_ms_) { | |
775 return true; | |
776 } | |
777 next_insert_packet_time_ms_ += kPacketSizeMs; | |
778 ++receive_packet_count_; | |
779 | |
780 // Encode new frame. | |
781 uint32_t input_timestamp = rtp_header_.header.timestamp; | |
782 while (info.encoded_bytes == 0) { | |
783 info = | |
784 isac_encoder_->Encode(input_timestamp, audio_loop_.GetNextBlock(), | |
785 max_encoded_bytes, encoded.get()); | |
786 input_timestamp += 160; // 10 ms at 16 kHz. | |
787 } | |
788 EXPECT_EQ(rtp_header_.header.timestamp + kPacketSizeSamples, | |
789 input_timestamp); | |
790 EXPECT_EQ(rtp_header_.header.timestamp, info.encoded_timestamp); | |
791 EXPECT_EQ(rtp_header_.header.payloadType, info.payload_type); | |
792 } | |
793 // Now we're not holding the crit sect when calling ACM. | |
794 | |
795 // Insert into ACM. | |
796 EXPECT_EQ(0, acm_->IncomingPacket(encoded.get(), info.encoded_bytes, | |
797 rtp_header_)); | |
798 | |
799 // Pull audio. | |
800 for (int i = 0; i < rtc::CheckedDivExact(kPacketSizeMs, 10); ++i) { | |
801 AudioFrame audio_frame; | |
802 EXPECT_EQ(0, acm_->PlayoutData10Ms(-1 /* default output frequency */, | |
803 &audio_frame)); | |
804 fake_clock_->AdvanceTimeMilliseconds(10); | |
805 } | |
806 rtp_utility_->Forward(&rtp_header_); | |
807 return true; | |
808 } | |
809 | |
810 static bool CbCodecRegistrationThread(void* context) { | |
811 return reinterpret_cast<AcmReRegisterIsacMtTestOldApi*>(context) | |
812 ->CbCodecRegistrationImpl(); | |
813 } | |
814 | |
815 bool CbCodecRegistrationImpl() { | |
816 SleepMs(1); | |
817 if (HasFatalFailure()) { | |
818 // End the test early if a fatal failure (ASSERT_*) has occurred. | |
819 test_complete_->Set(); | |
820 } | |
821 CriticalSectionScoped lock(crit_sect_.get()); | |
822 if (!codec_registered_ && | |
823 receive_packet_count_ > kRegisterAfterNumPackets) { | |
824 // Register the iSAC encoder. | |
825 EXPECT_EQ(0, acm_->RegisterSendCodec(codec_)); | |
826 codec_registered_ = true; | |
827 } | |
828 if (codec_registered_ && receive_packet_count_ > kNumPackets) { | |
829 test_complete_->Set(); | |
830 } | |
831 return true; | |
832 } | |
833 | |
834 rtc::scoped_ptr<PlatformThread> receive_thread_; | |
835 rtc::scoped_ptr<PlatformThread> codec_registration_thread_; | |
836 const rtc::scoped_ptr<EventWrapper> test_complete_; | |
837 const rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_; | |
838 bool codec_registered_ GUARDED_BY(crit_sect_); | |
839 int receive_packet_count_ GUARDED_BY(crit_sect_); | |
840 int64_t next_insert_packet_time_ms_ GUARDED_BY(crit_sect_); | |
841 rtc::scoped_ptr<AudioEncoderIsac> isac_encoder_; | |
842 rtc::scoped_ptr<SimulatedClock> fake_clock_; | |
843 test::AudioLoop audio_loop_; | |
844 }; | |
845 | |
846 TEST_F(AcmReRegisterIsacMtTestOldApi, DISABLED_ON_IOS(IF_ISAC(DoTest))) { | |
847 EXPECT_EQ(kEventSignaled, RunTest()); | |
848 } | |
849 | |
850 // Disabling all of these tests on iOS until file support has been added. | |
851 // See https://code.google.com/p/webrtc/issues/detail?id=4752 for details. | |
852 #if !defined(WEBRTC_IOS) | |
853 | |
854 class AcmReceiverBitExactnessOldApi : public ::testing::Test { | |
855 public: | |
856 static std::string PlatformChecksum(std::string win64, | |
857 std::string android, | |
858 std::string others) { | |
859 #if defined(_WIN32) && defined(WEBRTC_ARCH_64_BITS) | |
860 return win64; | |
861 #elif defined(WEBRTC_ANDROID) | |
862 return android; | |
863 #else | |
864 return others; | |
865 #endif | |
866 } | |
867 | |
868 protected: | |
869 struct ExternalDecoder { | |
870 int rtp_payload_type; | |
871 AudioDecoder* external_decoder; | |
872 int sample_rate_hz; | |
873 int num_channels; | |
874 }; | |
875 | |
876 void Run(int output_freq_hz, | |
877 const std::string& checksum_ref, | |
878 const std::vector<ExternalDecoder>& external_decoders) { | |
879 const std::string input_file_name = | |
880 webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); | |
881 rtc::scoped_ptr<test::RtpFileSource> packet_source( | |
882 test::RtpFileSource::Create(input_file_name)); | |
883 #ifdef WEBRTC_ANDROID | |
884 // Filter out iLBC and iSAC-swb since they are not supported on Android. | |
885 packet_source->FilterOutPayloadType(102); // iLBC. | |
886 packet_source->FilterOutPayloadType(104); // iSAC-swb. | |
887 #endif | |
888 | |
889 test::AudioChecksum checksum; | |
890 const std::string output_file_name = | |
891 webrtc::test::OutputPath() + | |
892 ::testing::UnitTest::GetInstance() | |
893 ->current_test_info() | |
894 ->test_case_name() + | |
895 "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() + | |
896 "_output.pcm"; | |
897 test::OutputAudioFile output_file(output_file_name); | |
898 test::AudioSinkFork output(&checksum, &output_file); | |
899 | |
900 test::AcmReceiveTestOldApi test( | |
901 packet_source.get(), | |
902 &output, | |
903 output_freq_hz, | |
904 test::AcmReceiveTestOldApi::kArbitraryChannels); | |
905 ASSERT_NO_FATAL_FAILURE(test.RegisterNetEqTestCodecs()); | |
906 for (const auto& ed : external_decoders) { | |
907 ASSERT_EQ(0, test.RegisterExternalReceiveCodec( | |
908 ed.rtp_payload_type, ed.external_decoder, | |
909 ed.sample_rate_hz, ed.num_channels)); | |
910 } | |
911 test.Run(); | |
912 | |
913 std::string checksum_string = checksum.Finish(); | |
914 EXPECT_EQ(checksum_ref, checksum_string); | |
915 } | |
916 }; | |
917 | |
918 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISAC)) && \ | |
919 defined(WEBRTC_CODEC_ILBC) && defined(WEBRTC_CODEC_G722) | |
920 #define IF_ALL_CODECS(x) x | |
921 #else | |
922 #define IF_ALL_CODECS(x) DISABLED_##x | |
923 #endif | |
924 | |
925 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
926 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
927 #define MAYBE_8kHzOutput DISABLED_8kHzOutput | |
928 #else | |
929 #define MAYBE_8kHzOutput 8kHzOutput | |
930 #endif | |
931 TEST_F(AcmReceiverBitExactnessOldApi, IF_ALL_CODECS(MAYBE_8kHzOutput)) { | |
932 Run(8000, PlatformChecksum("dcee98c623b147ebe1b40dd30efa896e", | |
933 "adc92e173f908f93b96ba5844209815a", | |
934 "908002dc01fc4eb1d2be24eb1d3f354b"), | |
935 std::vector<ExternalDecoder>()); | |
936 } | |
937 | |
938 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
939 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
940 #define MAYBE_16kHzOutput DISABLED_16kHzOutput | |
941 #else | |
942 #define MAYBE_16kHzOutput 16kHzOutput | |
943 #endif | |
944 TEST_F(AcmReceiverBitExactnessOldApi, IF_ALL_CODECS(MAYBE_16kHzOutput)) { | |
945 Run(16000, PlatformChecksum("f790e7a8cce4e2c8b7bb5e0e4c5dac0d", | |
946 "8cffa6abcb3e18e33b9d857666dff66a", | |
947 "a909560b5ca49fa472b17b7b277195e9"), | |
948 std::vector<ExternalDecoder>()); | |
949 } | |
950 | |
951 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
952 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
953 #define MAYBE_32kHzOutput DISABLED_32kHzOutput | |
954 #else | |
955 #define MAYBE_32kHzOutput 32kHzOutput | |
956 #endif | |
957 TEST_F(AcmReceiverBitExactnessOldApi, IF_ALL_CODECS(MAYBE_32kHzOutput)) { | |
958 Run(32000, PlatformChecksum("306e0d990ee6e92de3fbecc0123ece37", | |
959 "3e126fe894720c3f85edadcc91964ba5", | |
960 "441aab4b347fb3db4e9244337aca8d8e"), | |
961 std::vector<ExternalDecoder>()); | |
962 } | |
963 | |
964 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
965 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
966 #define MAYBE_48kHzOutput DISABLED_48kHzOutput | |
967 #else | |
968 #define MAYBE_48kHzOutput 48kHzOutput | |
969 #endif | |
970 TEST_F(AcmReceiverBitExactnessOldApi, IF_ALL_CODECS(MAYBE_48kHzOutput)) { | |
971 Run(48000, PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0", | |
972 "0155665e93067c4e89256b944dd11999", | |
973 "4ee2730fa1daae755e8a8fd3abd779ec"), | |
974 std::vector<ExternalDecoder>()); | |
975 } | |
976 | |
977 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
978 #if defined(WEBRTC_ANDROID) && defined(__aarch64__) | |
979 #define MAYBE_48kHzOutputExternalDecoder DISABLED_48kHzOutputExternalDecoder | |
980 #else | |
981 #define MAYBE_48kHzOutputExternalDecoder 48kHzOutputExternalDecoder | |
982 #endif | |
983 TEST_F(AcmReceiverBitExactnessOldApi, | |
984 IF_ALL_CODECS(MAYBE_48kHzOutputExternalDecoder)) { | |
985 AudioDecoderPcmU decoder(1); | |
986 MockAudioDecoder mock_decoder; | |
987 // Set expectations on the mock decoder and also delegate the calls to the | |
988 // real decoder. | |
989 EXPECT_CALL(mock_decoder, IncomingPacket(_, _, _, _, _)) | |
990 .Times(AtLeast(1)) | |
991 .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::IncomingPacket)); | |
992 EXPECT_CALL(mock_decoder, Channels()) | |
993 .Times(AtLeast(1)) | |
994 .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::Channels)); | |
995 EXPECT_CALL(mock_decoder, Decode(_, _, _, _, _, _)) | |
996 .Times(AtLeast(1)) | |
997 .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::Decode)); | |
998 EXPECT_CALL(mock_decoder, HasDecodePlc()) | |
999 .Times(AtLeast(1)) | |
1000 .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::HasDecodePlc)); | |
1001 EXPECT_CALL(mock_decoder, PacketDuration(_, _)) | |
1002 .Times(AtLeast(1)) | |
1003 .WillRepeatedly(Invoke(&decoder, &AudioDecoderPcmU::PacketDuration)); | |
1004 ExternalDecoder ed; | |
1005 ed.rtp_payload_type = 0; | |
1006 ed.external_decoder = &mock_decoder; | |
1007 ed.sample_rate_hz = 8000; | |
1008 ed.num_channels = 1; | |
1009 std::vector<ExternalDecoder> external_decoders; | |
1010 external_decoders.push_back(ed); | |
1011 | |
1012 Run(48000, PlatformChecksum("aa7c232f63a67b2a72703593bdd172e0", | |
1013 "0155665e93067c4e89256b944dd11999", | |
1014 "4ee2730fa1daae755e8a8fd3abd779ec"), | |
1015 external_decoders); | |
1016 | |
1017 EXPECT_CALL(mock_decoder, Die()); | |
1018 } | |
1019 | |
1020 // This test verifies bit exactness for the send-side of ACM. The test setup is | |
1021 // a chain of three different test classes: | |
1022 // | |
1023 // test::AcmSendTest -> AcmSenderBitExactness -> test::AcmReceiveTest | |
1024 // | |
1025 // The receiver side is driving the test by requesting new packets from | |
1026 // AcmSenderBitExactness::NextPacket(). This method, in turn, asks for the | |
1027 // packet from test::AcmSendTest::NextPacket, which inserts audio from the | |
1028 // input file until one packet is produced. (The input file loops indefinitely.) | |
1029 // Before passing the packet to the receiver, this test class verifies the | |
1030 // packet header and updates a payload checksum with the new payload. The | |
1031 // decoded output from the receiver is also verified with a (separate) checksum. | |
1032 class AcmSenderBitExactnessOldApi : public ::testing::Test, | |
1033 public test::PacketSource { | |
1034 protected: | |
1035 static const int kTestDurationMs = 1000; | |
1036 | |
1037 AcmSenderBitExactnessOldApi() | |
1038 : frame_size_rtp_timestamps_(0), | |
1039 packet_count_(0), | |
1040 payload_type_(0), | |
1041 last_sequence_number_(0), | |
1042 last_timestamp_(0) {} | |
1043 | |
1044 // Sets up the test::AcmSendTest object. Returns true on success, otherwise | |
1045 // false. | |
1046 bool SetUpSender() { | |
1047 const std::string input_file_name = | |
1048 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); | |
1049 // Note that |audio_source_| will loop forever. The test duration is set | |
1050 // explicitly by |kTestDurationMs|. | |
1051 audio_source_.reset(new test::InputAudioFile(input_file_name)); | |
1052 static const int kSourceRateHz = 32000; | |
1053 send_test_.reset(new test::AcmSendTestOldApi( | |
1054 audio_source_.get(), kSourceRateHz, kTestDurationMs)); | |
1055 return send_test_.get() != NULL; | |
1056 } | |
1057 | |
1058 // Registers a send codec in the test::AcmSendTest object. Returns true on | |
1059 // success, false on failure. | |
1060 bool RegisterSendCodec(const char* payload_name, | |
1061 int sampling_freq_hz, | |
1062 int channels, | |
1063 int payload_type, | |
1064 int frame_size_samples, | |
1065 int frame_size_rtp_timestamps) { | |
1066 payload_type_ = payload_type; | |
1067 frame_size_rtp_timestamps_ = frame_size_rtp_timestamps; | |
1068 return send_test_->RegisterCodec(payload_name, | |
1069 sampling_freq_hz, | |
1070 channels, | |
1071 payload_type, | |
1072 frame_size_samples); | |
1073 } | |
1074 | |
1075 bool RegisterExternalSendCodec(AudioEncoder* external_speech_encoder, | |
1076 int payload_type) { | |
1077 payload_type_ = payload_type; | |
1078 frame_size_rtp_timestamps_ = | |
1079 external_speech_encoder->Num10MsFramesInNextPacket() * | |
1080 external_speech_encoder->RtpTimestampRateHz() / 100; | |
1081 return send_test_->RegisterExternalCodec(external_speech_encoder); | |
1082 } | |
1083 | |
1084 // Runs the test. SetUpSender() and RegisterSendCodec() must have been called | |
1085 // before calling this method. | |
1086 void Run(const std::string& audio_checksum_ref, | |
1087 const std::string& payload_checksum_ref, | |
1088 int expected_packets, | |
1089 test::AcmReceiveTestOldApi::NumOutputChannels expected_channels) { | |
1090 // Set up the receiver used to decode the packets and verify the decoded | |
1091 // output. | |
1092 test::AudioChecksum audio_checksum; | |
1093 const std::string output_file_name = | |
1094 webrtc::test::OutputPath() + | |
1095 ::testing::UnitTest::GetInstance() | |
1096 ->current_test_info() | |
1097 ->test_case_name() + | |
1098 "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() + | |
1099 "_output.pcm"; | |
1100 test::OutputAudioFile output_file(output_file_name); | |
1101 // Have the output audio sent both to file and to the checksum calculator. | |
1102 test::AudioSinkFork output(&audio_checksum, &output_file); | |
1103 const int kOutputFreqHz = 8000; | |
1104 test::AcmReceiveTestOldApi receive_test( | |
1105 this, &output, kOutputFreqHz, expected_channels); | |
1106 ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs()); | |
1107 | |
1108 // This is where the actual test is executed. | |
1109 receive_test.Run(); | |
1110 | |
1111 // Extract and verify the audio checksum. | |
1112 std::string checksum_string = audio_checksum.Finish(); | |
1113 EXPECT_EQ(audio_checksum_ref, checksum_string); | |
1114 | |
1115 // Extract and verify the payload checksum. | |
1116 char checksum_result[rtc::Md5Digest::kSize]; | |
1117 payload_checksum_.Finish(checksum_result, rtc::Md5Digest::kSize); | |
1118 checksum_string = rtc::hex_encode(checksum_result, rtc::Md5Digest::kSize); | |
1119 EXPECT_EQ(payload_checksum_ref, checksum_string); | |
1120 | |
1121 // Verify number of packets produced. | |
1122 EXPECT_EQ(expected_packets, packet_count_); | |
1123 } | |
1124 | |
1125 // Returns a pointer to the next packet. Returns NULL if the source is | |
1126 // depleted (i.e., the test duration is exceeded), or if an error occurred. | |
1127 // Inherited from test::PacketSource. | |
1128 test::Packet* NextPacket() override { | |
1129 // Get the next packet from AcmSendTest. Ownership of |packet| is | |
1130 // transferred to this method. | |
1131 test::Packet* packet = send_test_->NextPacket(); | |
1132 if (!packet) | |
1133 return NULL; | |
1134 | |
1135 VerifyPacket(packet); | |
1136 // TODO(henrik.lundin) Save the packet to file as well. | |
1137 | |
1138 // Pass it on to the caller. The caller becomes the owner of |packet|. | |
1139 return packet; | |
1140 } | |
1141 | |
1142 // Verifies the packet. | |
1143 void VerifyPacket(const test::Packet* packet) { | |
1144 EXPECT_TRUE(packet->valid_header()); | |
1145 // (We can check the header fields even if valid_header() is false.) | |
1146 EXPECT_EQ(payload_type_, packet->header().payloadType); | |
1147 if (packet_count_ > 0) { | |
1148 // This is not the first packet. | |
1149 uint16_t sequence_number_diff = | |
1150 packet->header().sequenceNumber - last_sequence_number_; | |
1151 EXPECT_EQ(1, sequence_number_diff); | |
1152 uint32_t timestamp_diff = packet->header().timestamp - last_timestamp_; | |
1153 EXPECT_EQ(frame_size_rtp_timestamps_, timestamp_diff); | |
1154 } | |
1155 ++packet_count_; | |
1156 last_sequence_number_ = packet->header().sequenceNumber; | |
1157 last_timestamp_ = packet->header().timestamp; | |
1158 // Update the checksum. | |
1159 payload_checksum_.Update(packet->payload(), packet->payload_length_bytes()); | |
1160 } | |
1161 | |
1162 void SetUpTest(const char* codec_name, | |
1163 int codec_sample_rate_hz, | |
1164 int channels, | |
1165 int payload_type, | |
1166 int codec_frame_size_samples, | |
1167 int codec_frame_size_rtp_timestamps) { | |
1168 ASSERT_TRUE(SetUpSender()); | |
1169 ASSERT_TRUE(RegisterSendCodec(codec_name, | |
1170 codec_sample_rate_hz, | |
1171 channels, | |
1172 payload_type, | |
1173 codec_frame_size_samples, | |
1174 codec_frame_size_rtp_timestamps)); | |
1175 } | |
1176 | |
1177 void SetUpTestExternalEncoder(AudioEncoder* external_speech_encoder, | |
1178 int payload_type) { | |
1179 ASSERT_TRUE(SetUpSender()); | |
1180 ASSERT_TRUE( | |
1181 RegisterExternalSendCodec(external_speech_encoder, payload_type)); | |
1182 } | |
1183 | |
1184 rtc::scoped_ptr<test::AcmSendTestOldApi> send_test_; | |
1185 rtc::scoped_ptr<test::InputAudioFile> audio_source_; | |
1186 uint32_t frame_size_rtp_timestamps_; | |
1187 int packet_count_; | |
1188 uint8_t payload_type_; | |
1189 uint16_t last_sequence_number_; | |
1190 uint32_t last_timestamp_; | |
1191 rtc::Md5Digest payload_checksum_; | |
1192 }; | |
1193 | |
1194 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
1195 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
1196 #define MAYBE_IsacWb30ms DISABLED_IsacWb30ms | |
1197 #else | |
1198 #define MAYBE_IsacWb30ms IsacWb30ms | |
1199 #endif | |
1200 TEST_F(AcmSenderBitExactnessOldApi, IF_ISAC(MAYBE_IsacWb30ms)) { | |
1201 ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 480, 480)); | |
1202 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1203 "c7e5bdadfa2871df95639fcc297cf23d", | |
1204 "0499ca260390769b3172136faad925b9", | |
1205 "0b58f9eeee43d5891f5f6c75e77984a3"), | |
1206 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1207 "d42cb5195463da26c8129bbfe73a22e6", | |
1208 "83de248aea9c3c2bd680b6952401b4ca", | |
1209 "3c79f16f34218271f3dca4e2b1dfe1bb"), | |
1210 33, | |
1211 test::AcmReceiveTestOldApi::kMonoOutput); | |
1212 } | |
1213 | |
1214 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
1215 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
1216 #define MAYBE_IsacWb60ms DISABLED_IsacWb60ms | |
1217 #else | |
1218 #define MAYBE_IsacWb60ms IsacWb60ms | |
1219 #endif | |
1220 TEST_F(AcmSenderBitExactnessOldApi, IF_ISAC(MAYBE_IsacWb60ms)) { | |
1221 ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 960, 960)); | |
1222 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1223 "14d63c5f08127d280e722e3191b73bdd", | |
1224 "8da003e16c5371af2dc2be79a50f9076", | |
1225 "1ad29139a04782a33daad8c2b9b35875"), | |
1226 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1227 "ebe04a819d3a9d83a83a17f271e1139a", | |
1228 "97aeef98553b5a4b5a68f8b716e8eaf0", | |
1229 "9e0a0ab743ad987b55b8e14802769c56"), | |
1230 16, | |
1231 test::AcmReceiveTestOldApi::kMonoOutput); | |
1232 } | |
1233 | |
1234 #ifdef WEBRTC_CODEC_ISAC | |
1235 #define IF_ISAC_FLOAT(x) x | |
1236 #else | |
1237 #define IF_ISAC_FLOAT(x) DISABLED_##x | |
1238 #endif | |
1239 | |
1240 TEST_F(AcmSenderBitExactnessOldApi, | |
1241 DISABLED_ON_ANDROID(IF_ISAC_FLOAT(IsacSwb30ms))) { | |
1242 ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 32000, 1, 104, 960, 960)); | |
1243 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1244 "2b3c387d06f00b7b7aad4c9be56fb83d", | |
1245 "", | |
1246 "5683b58da0fbf2063c7adc2e6bfb3fb8"), | |
1247 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1248 "bcc2041e7744c7ebd9f701866856849c", | |
1249 "", | |
1250 "ce86106a93419aefb063097108ec94ab"), | |
1251 33, test::AcmReceiveTestOldApi::kMonoOutput); | |
1252 } | |
1253 | |
1254 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_8000khz_10ms) { | |
1255 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); | |
1256 Run("de4a98e1406f8b798d99cd0704e862e2", | |
1257 "c1edd36339ce0326cc4550041ad719a0", | |
1258 100, | |
1259 test::AcmReceiveTestOldApi::kMonoOutput); | |
1260 } | |
1261 | |
1262 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_16000khz_10ms) { | |
1263 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 1, 108, 160, 160)); | |
1264 Run("ae646d7b68384a1269cc080dd4501916", | |
1265 "ad786526383178b08d80d6eee06e9bad", | |
1266 100, | |
1267 test::AcmReceiveTestOldApi::kMonoOutput); | |
1268 } | |
1269 | |
1270 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_32000khz_10ms) { | |
1271 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 1, 109, 320, 320)); | |
1272 Run("7fe325e8fbaf755e3c5df0b11a4774fb", | |
1273 "5ef82ea885e922263606c6fdbc49f651", | |
1274 100, | |
1275 test::AcmReceiveTestOldApi::kMonoOutput); | |
1276 } | |
1277 | |
1278 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_8000khz_10ms) { | |
1279 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 2, 111, 80, 80)); | |
1280 Run("fb263b74e7ac3de915474d77e4744ceb", | |
1281 "62ce5adb0d4965d0a52ec98ae7f98974", | |
1282 100, | |
1283 test::AcmReceiveTestOldApi::kStereoOutput); | |
1284 } | |
1285 | |
1286 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_16000khz_10ms) { | |
1287 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 2, 112, 160, 160)); | |
1288 Run("d09e9239553649d7ac93e19d304281fd", | |
1289 "41ca8edac4b8c71cd54fd9f25ec14870", | |
1290 100, | |
1291 test::AcmReceiveTestOldApi::kStereoOutput); | |
1292 } | |
1293 | |
1294 TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_32000khz_10ms) { | |
1295 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 2, 113, 320, 320)); | |
1296 Run("5f025d4f390982cc26b3d92fe02e3044", | |
1297 "50e58502fb04421bf5b857dda4c96879", | |
1298 100, | |
1299 test::AcmReceiveTestOldApi::kStereoOutput); | |
1300 } | |
1301 | |
1302 TEST_F(AcmSenderBitExactnessOldApi, Pcmu_20ms) { | |
1303 ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMU", 8000, 1, 0, 160, 160)); | |
1304 Run("81a9d4c0bb72e9becc43aef124c981e9", | |
1305 "8f9b8750bd80fe26b6cbf6659b89f0f9", | |
1306 50, | |
1307 test::AcmReceiveTestOldApi::kMonoOutput); | |
1308 } | |
1309 | |
1310 TEST_F(AcmSenderBitExactnessOldApi, Pcma_20ms) { | |
1311 ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMA", 8000, 1, 8, 160, 160)); | |
1312 Run("39611f798969053925a49dc06d08de29", | |
1313 "6ad745e55aa48981bfc790d0eeef2dd1", | |
1314 50, | |
1315 test::AcmReceiveTestOldApi::kMonoOutput); | |
1316 } | |
1317 | |
1318 TEST_F(AcmSenderBitExactnessOldApi, Pcmu_stereo_20ms) { | |
1319 ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMU", 8000, 2, 110, 160, 160)); | |
1320 Run("437bec032fdc5cbaa0d5175430af7b18", | |
1321 "60b6f25e8d1e74cb679cfe756dd9bca5", | |
1322 50, | |
1323 test::AcmReceiveTestOldApi::kStereoOutput); | |
1324 } | |
1325 | |
1326 TEST_F(AcmSenderBitExactnessOldApi, Pcma_stereo_20ms) { | |
1327 ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMA", 8000, 2, 118, 160, 160)); | |
1328 Run("a5c6d83c5b7cedbeff734238220a4b0c", | |
1329 "92b282c83efd20e7eeef52ba40842cf7", | |
1330 50, | |
1331 test::AcmReceiveTestOldApi::kStereoOutput); | |
1332 } | |
1333 | |
1334 #ifdef WEBRTC_CODEC_ILBC | |
1335 #define IF_ILBC(x) x | |
1336 #else | |
1337 #define IF_ILBC(x) DISABLED_##x | |
1338 #endif | |
1339 | |
1340 TEST_F(AcmSenderBitExactnessOldApi, DISABLED_ON_ANDROID(IF_ILBC(Ilbc_30ms))) { | |
1341 ASSERT_NO_FATAL_FAILURE(SetUpTest("ILBC", 8000, 1, 102, 240, 240)); | |
1342 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1343 "7b6ec10910debd9af08011d3ed5249f7", | |
1344 "android_audio", | |
1345 "7b6ec10910debd9af08011d3ed5249f7"), | |
1346 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1347 "cfae2e9f6aba96e145f2bcdd5050ce78", | |
1348 "android_payload", | |
1349 "cfae2e9f6aba96e145f2bcdd5050ce78"), | |
1350 33, | |
1351 test::AcmReceiveTestOldApi::kMonoOutput); | |
1352 } | |
1353 | |
1354 #ifdef WEBRTC_CODEC_G722 | |
1355 #define IF_G722(x) x | |
1356 #else | |
1357 #define IF_G722(x) DISABLED_##x | |
1358 #endif | |
1359 | |
1360 TEST_F(AcmSenderBitExactnessOldApi, DISABLED_ON_ANDROID(IF_G722(G722_20ms))) { | |
1361 ASSERT_NO_FATAL_FAILURE(SetUpTest("G722", 16000, 1, 9, 320, 160)); | |
1362 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1363 "7d759436f2533582950d148b5161a36c", | |
1364 "android_audio", | |
1365 "7d759436f2533582950d148b5161a36c"), | |
1366 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1367 "fc68a87e1380614e658087cb35d5ca10", | |
1368 "android_payload", | |
1369 "fc68a87e1380614e658087cb35d5ca10"), | |
1370 50, | |
1371 test::AcmReceiveTestOldApi::kMonoOutput); | |
1372 } | |
1373 | |
1374 TEST_F(AcmSenderBitExactnessOldApi, | |
1375 DISABLED_ON_ANDROID(IF_G722(G722_stereo_20ms))) { | |
1376 ASSERT_NO_FATAL_FAILURE(SetUpTest("G722", 16000, 2, 119, 320, 160)); | |
1377 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1378 "7190ee718ab3d80eca181e5f7140c210", | |
1379 "android_audio", | |
1380 "7190ee718ab3d80eca181e5f7140c210"), | |
1381 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1382 "66516152eeaa1e650ad94ff85f668dac", | |
1383 "android_payload", | |
1384 "66516152eeaa1e650ad94ff85f668dac"), | |
1385 50, | |
1386 test::AcmReceiveTestOldApi::kStereoOutput); | |
1387 } | |
1388 | |
1389 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
1390 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
1391 #define MAYBE_Opus_stereo_20ms DISABLED_Opus_stereo_20ms | |
1392 #else | |
1393 #define MAYBE_Opus_stereo_20ms Opus_stereo_20ms | |
1394 #endif | |
1395 TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms) { | |
1396 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960)); | |
1397 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1398 "855041f2490b887302bce9d544731849", | |
1399 "1e1a0fce893fef2d66886a7f09e2ebce", | |
1400 "855041f2490b887302bce9d544731849"), | |
1401 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1402 "d781cce1ab986b618d0da87226cdde30", | |
1403 "1a1fe04dd12e755949987c8d729fb3e0", | |
1404 "d781cce1ab986b618d0da87226cdde30"), | |
1405 50, | |
1406 test::AcmReceiveTestOldApi::kStereoOutput); | |
1407 } | |
1408 | |
1409 // Fails Android ARM64. https://code.google.com/p/webrtc/issues/detail?id=4199 | |
1410 #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM64) | |
1411 #define MAYBE_Opus_stereo_20ms_voip DISABLED_Opus_stereo_20ms_voip | |
1412 #else | |
1413 #define MAYBE_Opus_stereo_20ms_voip Opus_stereo_20ms_voip | |
1414 #endif | |
1415 TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Opus_stereo_20ms_voip) { | |
1416 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 2, 120, 960, 960)); | |
1417 // If not set, default will be kAudio in case of stereo. | |
1418 EXPECT_EQ(0, send_test_->acm()->SetOpusApplication(kVoip)); | |
1419 Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1420 "9b9e12bc3cc793740966e11cbfa8b35b", | |
1421 "57412a4b5771d19ff03ec35deffe7067", | |
1422 "9b9e12bc3cc793740966e11cbfa8b35b"), | |
1423 AcmReceiverBitExactnessOldApi::PlatformChecksum( | |
1424 "c7340b1189652ab6b5e80dade7390cb4", | |
1425 "cdfe85939c411d12b61701c566e22d26", | |
1426 "c7340b1189652ab6b5e80dade7390cb4"), | |
1427 50, | |
1428 test::AcmReceiveTestOldApi::kStereoOutput); | |
1429 } | |
1430 | |
1431 // This test is for verifying the SetBitRate function. The bitrate is changed at | |
1432 // the beginning, and the number of generated bytes are checked. | |
1433 class AcmSetBitRateOldApi : public ::testing::Test { | |
1434 protected: | |
1435 static const int kTestDurationMs = 1000; | |
1436 | |
1437 // Sets up the test::AcmSendTest object. Returns true on success, otherwise | |
1438 // false. | |
1439 bool SetUpSender() { | |
1440 const std::string input_file_name = | |
1441 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); | |
1442 // Note that |audio_source_| will loop forever. The test duration is set | |
1443 // explicitly by |kTestDurationMs|. | |
1444 audio_source_.reset(new test::InputAudioFile(input_file_name)); | |
1445 static const int kSourceRateHz = 32000; | |
1446 send_test_.reset(new test::AcmSendTestOldApi( | |
1447 audio_source_.get(), kSourceRateHz, kTestDurationMs)); | |
1448 return send_test_.get(); | |
1449 } | |
1450 | |
1451 // Registers a send codec in the test::AcmSendTest object. Returns true on | |
1452 // success, false on failure. | |
1453 virtual bool RegisterSendCodec(const char* payload_name, | |
1454 int sampling_freq_hz, | |
1455 int channels, | |
1456 int payload_type, | |
1457 int frame_size_samples, | |
1458 int frame_size_rtp_timestamps) { | |
1459 return send_test_->RegisterCodec(payload_name, sampling_freq_hz, channels, | |
1460 payload_type, frame_size_samples); | |
1461 } | |
1462 | |
1463 // Runs the test. SetUpSender() and RegisterSendCodec() must have been called | |
1464 // before calling this method. | |
1465 void Run(int target_bitrate_bps, int expected_total_bits) { | |
1466 ASSERT_TRUE(send_test_->acm()); | |
1467 send_test_->acm()->SetBitRate(target_bitrate_bps); | |
1468 int nr_bytes = 0; | |
1469 while (test::Packet* next_packet = send_test_->NextPacket()) { | |
1470 nr_bytes += next_packet->payload_length_bytes(); | |
1471 delete next_packet; | |
1472 } | |
1473 EXPECT_EQ(expected_total_bits, nr_bytes * 8); | |
1474 } | |
1475 | |
1476 void SetUpTest(const char* codec_name, | |
1477 int codec_sample_rate_hz, | |
1478 int channels, | |
1479 int payload_type, | |
1480 int codec_frame_size_samples, | |
1481 int codec_frame_size_rtp_timestamps) { | |
1482 ASSERT_TRUE(SetUpSender()); | |
1483 ASSERT_TRUE(RegisterSendCodec(codec_name, codec_sample_rate_hz, channels, | |
1484 payload_type, codec_frame_size_samples, | |
1485 codec_frame_size_rtp_timestamps)); | |
1486 } | |
1487 | |
1488 rtc::scoped_ptr<test::AcmSendTestOldApi> send_test_; | |
1489 rtc::scoped_ptr<test::InputAudioFile> audio_source_; | |
1490 }; | |
1491 | |
1492 TEST_F(AcmSetBitRateOldApi, Opus_48khz_20ms_10kbps) { | |
1493 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960)); | |
1494 #if defined(WEBRTC_ANDROID) | |
1495 Run(10000, 9328); | |
1496 #else | |
1497 Run(10000, 9072); | |
1498 #endif // WEBRTC_ANDROID | |
1499 | |
1500 } | |
1501 | |
1502 TEST_F(AcmSetBitRateOldApi, Opus_48khz_20ms_50kbps) { | |
1503 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960)); | |
1504 #if defined(WEBRTC_ANDROID) | |
1505 Run(50000, 47952); | |
1506 #else | |
1507 Run(50000, 49600); | |
1508 #endif // WEBRTC_ANDROID | |
1509 } | |
1510 | |
1511 // The result on the Android platforms is inconsistent for this test case. | |
1512 // On android_rel the result is different from android and android arm64 rel. | |
1513 TEST_F(AcmSetBitRateOldApi, DISABLED_ON_ANDROID(Opus_48khz_20ms_100kbps)) { | |
1514 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960)); | |
1515 Run(100000, 100888); | |
1516 } | |
1517 | |
1518 // These next 2 tests ensure that the SetBitRate function has no effect on PCM | |
1519 TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_8kbps) { | |
1520 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); | |
1521 Run(8000, 128000); | |
1522 } | |
1523 | |
1524 TEST_F(AcmSetBitRateOldApi, Pcm16_8khz_10ms_32kbps) { | |
1525 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); | |
1526 Run(32000, 128000); | |
1527 } | |
1528 | |
1529 // This test is for verifying the SetBitRate function. The bitrate is changed | |
1530 // in the middle, and the number of generated bytes are before and after the | |
1531 // change are checked. | |
1532 class AcmChangeBitRateOldApi : public AcmSetBitRateOldApi { | |
1533 protected: | |
1534 AcmChangeBitRateOldApi() : sampling_freq_hz_(0), frame_size_samples_(0) {} | |
1535 | |
1536 // Registers a send codec in the test::AcmSendTest object. Returns true on | |
1537 // success, false on failure. | |
1538 bool RegisterSendCodec(const char* payload_name, | |
1539 int sampling_freq_hz, | |
1540 int channels, | |
1541 int payload_type, | |
1542 int frame_size_samples, | |
1543 int frame_size_rtp_timestamps) override { | |
1544 frame_size_samples_ = frame_size_samples; | |
1545 sampling_freq_hz_ = sampling_freq_hz; | |
1546 return AcmSetBitRateOldApi::RegisterSendCodec( | |
1547 payload_name, sampling_freq_hz, channels, payload_type, | |
1548 frame_size_samples, frame_size_rtp_timestamps); | |
1549 } | |
1550 | |
1551 // Runs the test. SetUpSender() and RegisterSendCodec() must have been called | |
1552 // before calling this method. | |
1553 void Run(int target_bitrate_bps, | |
1554 int expected_before_switch_bits, | |
1555 int expected_after_switch_bits) { | |
1556 ASSERT_TRUE(send_test_->acm()); | |
1557 int nr_packets = | |
1558 sampling_freq_hz_ * kTestDurationMs / (frame_size_samples_ * 1000); | |
1559 int nr_bytes_before = 0, nr_bytes_after = 0; | |
1560 int packet_counter = 0; | |
1561 while (test::Packet* next_packet = send_test_->NextPacket()) { | |
1562 if (packet_counter == nr_packets / 2) | |
1563 send_test_->acm()->SetBitRate(target_bitrate_bps); | |
1564 if (packet_counter < nr_packets / 2) | |
1565 nr_bytes_before += next_packet->payload_length_bytes(); | |
1566 else | |
1567 nr_bytes_after += next_packet->payload_length_bytes(); | |
1568 packet_counter++; | |
1569 delete next_packet; | |
1570 } | |
1571 EXPECT_EQ(expected_before_switch_bits, nr_bytes_before * 8); | |
1572 EXPECT_EQ(expected_after_switch_bits, nr_bytes_after * 8); | |
1573 } | |
1574 | |
1575 uint32_t sampling_freq_hz_; | |
1576 uint32_t frame_size_samples_; | |
1577 }; | |
1578 | |
1579 TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_10kbps) { | |
1580 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960)); | |
1581 #if defined(WEBRTC_ANDROID) | |
1582 Run(10000, 32200, 5496); | |
1583 #else | |
1584 Run(10000, 32200, 5432); | |
1585 #endif // WEBRTC_ANDROID | |
1586 } | |
1587 | |
1588 TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_50kbps) { | |
1589 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960)); | |
1590 #if defined(WEBRTC_ANDROID) | |
1591 Run(50000, 32200, 24912); | |
1592 #else | |
1593 Run(50000, 32200, 24792); | |
1594 #endif // WEBRTC_ANDROID | |
1595 } | |
1596 | |
1597 TEST_F(AcmChangeBitRateOldApi, Opus_48khz_20ms_100kbps) { | |
1598 ASSERT_NO_FATAL_FAILURE(SetUpTest("opus", 48000, 1, 107, 960, 960)); | |
1599 #if defined(WEBRTC_ANDROID) | |
1600 Run(100000, 32200, 51480); | |
1601 #else | |
1602 Run(100000, 32200, 50584); | |
1603 #endif // WEBRTC_ANDROID | |
1604 } | |
1605 | |
1606 // These next 2 tests ensure that the SetBitRate function has no effect on PCM | |
1607 TEST_F(AcmChangeBitRateOldApi, Pcm16_8khz_10ms_8kbps) { | |
1608 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); | |
1609 Run(8000, 64000, 64000); | |
1610 } | |
1611 | |
1612 TEST_F(AcmChangeBitRateOldApi, Pcm16_8khz_10ms_32kbps) { | |
1613 ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); | |
1614 Run(32000, 64000, 64000); | |
1615 } | |
1616 | |
1617 TEST_F(AcmSenderBitExactnessOldApi, External_Pcmu_20ms) { | |
1618 CodecInst codec_inst; | |
1619 codec_inst.channels = 1; | |
1620 codec_inst.pacsize = 160; | |
1621 codec_inst.pltype = 0; | |
1622 AudioEncoderPcmU encoder(codec_inst); | |
1623 MockAudioEncoder mock_encoder; | |
1624 // Set expectations on the mock encoder and also delegate the calls to the | |
1625 // real encoder. | |
1626 EXPECT_CALL(mock_encoder, MaxEncodedBytes()) | |
1627 .Times(AtLeast(1)) | |
1628 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::MaxEncodedBytes)); | |
1629 EXPECT_CALL(mock_encoder, SampleRateHz()) | |
1630 .Times(AtLeast(1)) | |
1631 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::SampleRateHz)); | |
1632 EXPECT_CALL(mock_encoder, NumChannels()) | |
1633 .Times(AtLeast(1)) | |
1634 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::NumChannels)); | |
1635 EXPECT_CALL(mock_encoder, RtpTimestampRateHz()) | |
1636 .Times(AtLeast(1)) | |
1637 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::RtpTimestampRateHz)); | |
1638 EXPECT_CALL(mock_encoder, Num10MsFramesInNextPacket()) | |
1639 .Times(AtLeast(1)) | |
1640 .WillRepeatedly( | |
1641 Invoke(&encoder, &AudioEncoderPcmU::Num10MsFramesInNextPacket)); | |
1642 EXPECT_CALL(mock_encoder, Max10MsFramesInAPacket()) | |
1643 .Times(AtLeast(1)) | |
1644 .WillRepeatedly( | |
1645 Invoke(&encoder, &AudioEncoderPcmU::Max10MsFramesInAPacket)); | |
1646 EXPECT_CALL(mock_encoder, GetTargetBitrate()) | |
1647 .Times(AtLeast(1)) | |
1648 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::GetTargetBitrate)); | |
1649 EXPECT_CALL(mock_encoder, EncodeInternal(_, _, _, _)) | |
1650 .Times(AtLeast(1)) | |
1651 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::EncodeInternal)); | |
1652 EXPECT_CALL(mock_encoder, SetFec(_)) | |
1653 .Times(AtLeast(1)) | |
1654 .WillRepeatedly(Invoke(&encoder, &AudioEncoderPcmU::SetFec)); | |
1655 ASSERT_NO_FATAL_FAILURE( | |
1656 SetUpTestExternalEncoder(&mock_encoder, codec_inst.pltype)); | |
1657 Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9", | |
1658 50, test::AcmReceiveTestOldApi::kMonoOutput); | |
1659 } | |
1660 | |
1661 // This test fixture is implemented to run ACM and change the desired output | |
1662 // frequency during the call. The input packets are simply PCM16b-wb encoded | |
1663 // payloads with a constant value of |kSampleValue|. The test fixture itself | |
1664 // acts as PacketSource in between the receive test class and the constant- | |
1665 // payload packet source class. The output is both written to file, and analyzed | |
1666 // in this test fixture. | |
1667 class AcmSwitchingOutputFrequencyOldApi : public ::testing::Test, | |
1668 public test::PacketSource, | |
1669 public test::AudioSink { | |
1670 protected: | |
1671 static const size_t kTestNumPackets = 50; | |
1672 static const int kEncodedSampleRateHz = 16000; | |
1673 static const size_t kPayloadLenSamples = 30 * kEncodedSampleRateHz / 1000; | |
1674 static const int kPayloadType = 108; // Default payload type for PCM16b-wb. | |
1675 | |
1676 AcmSwitchingOutputFrequencyOldApi() | |
1677 : first_output_(true), | |
1678 num_packets_(0), | |
1679 packet_source_(kPayloadLenSamples, | |
1680 kSampleValue, | |
1681 kEncodedSampleRateHz, | |
1682 kPayloadType), | |
1683 output_freq_2_(0), | |
1684 has_toggled_(false) {} | |
1685 | |
1686 void Run(int output_freq_1, int output_freq_2, int toggle_period_ms) { | |
1687 // Set up the receiver used to decode the packets and verify the decoded | |
1688 // output. | |
1689 const std::string output_file_name = | |
1690 webrtc::test::OutputPath() + | |
1691 ::testing::UnitTest::GetInstance() | |
1692 ->current_test_info() | |
1693 ->test_case_name() + | |
1694 "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() + | |
1695 "_output.pcm"; | |
1696 test::OutputAudioFile output_file(output_file_name); | |
1697 // Have the output audio sent both to file and to the WriteArray method in | |
1698 // this class. | |
1699 test::AudioSinkFork output(this, &output_file); | |
1700 test::AcmReceiveTestToggleOutputFreqOldApi receive_test( | |
1701 this, | |
1702 &output, | |
1703 output_freq_1, | |
1704 output_freq_2, | |
1705 toggle_period_ms, | |
1706 test::AcmReceiveTestOldApi::kMonoOutput); | |
1707 ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs()); | |
1708 output_freq_2_ = output_freq_2; | |
1709 | |
1710 // This is where the actual test is executed. | |
1711 receive_test.Run(); | |
1712 } | |
1713 | |
1714 // Inherited from test::PacketSource. | |
1715 test::Packet* NextPacket() override { | |
1716 // Check if it is time to terminate the test. The packet source is of type | |
1717 // ConstantPcmPacketSource, which is infinite, so we must end the test | |
1718 // "manually". | |
1719 if (num_packets_++ > kTestNumPackets) { | |
1720 EXPECT_TRUE(has_toggled_); | |
1721 return NULL; // Test ended. | |
1722 } | |
1723 | |
1724 // Get the next packet from the source. | |
1725 return packet_source_.NextPacket(); | |
1726 } | |
1727 | |
1728 // Inherited from test::AudioSink. | |
1729 bool WriteArray(const int16_t* audio, size_t num_samples) { | |
1730 // Skip checking the first output frame, since it has a number of zeros | |
1731 // due to how NetEq is initialized. | |
1732 if (first_output_) { | |
1733 first_output_ = false; | |
1734 return true; | |
1735 } | |
1736 for (size_t i = 0; i < num_samples; ++i) { | |
1737 EXPECT_EQ(kSampleValue, audio[i]); | |
1738 } | |
1739 if (num_samples == | |
1740 static_cast<size_t>(output_freq_2_ / 100)) // Size of 10 ms frame. | |
1741 has_toggled_ = true; | |
1742 // The return value does not say if the values match the expectation, just | |
1743 // that the method could process the samples. | |
1744 return true; | |
1745 } | |
1746 | |
1747 const int16_t kSampleValue = 1000; | |
1748 bool first_output_; | |
1749 size_t num_packets_; | |
1750 test::ConstantPcmPacketSource packet_source_; | |
1751 int output_freq_2_; | |
1752 bool has_toggled_; | |
1753 }; | |
1754 | |
1755 TEST_F(AcmSwitchingOutputFrequencyOldApi, TestWithoutToggling) { | |
1756 Run(16000, 16000, 1000); | |
1757 } | |
1758 | |
1759 TEST_F(AcmSwitchingOutputFrequencyOldApi, Toggle16KhzTo32Khz) { | |
1760 Run(16000, 32000, 1000); | |
1761 } | |
1762 | |
1763 TEST_F(AcmSwitchingOutputFrequencyOldApi, Toggle32KhzTo16Khz) { | |
1764 Run(32000, 16000, 1000); | |
1765 } | |
1766 | |
1767 TEST_F(AcmSwitchingOutputFrequencyOldApi, Toggle16KhzTo8Khz) { | |
1768 Run(16000, 8000, 1000); | |
1769 } | |
1770 | |
1771 TEST_F(AcmSwitchingOutputFrequencyOldApi, Toggle8KhzTo16Khz) { | |
1772 Run(8000, 16000, 1000); | |
1773 } | |
1774 | |
1775 #endif | |
1776 | |
1777 } // namespace webrtc | |
OLD | NEW |