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