OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 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 "webrtc/modules/audio_coding/main/test/TestAllCodecs.h" | |
12 | |
13 #include <cstdio> | |
14 #include <limits> | |
15 #include <string> | |
16 | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 #include "webrtc/common_types.h" | |
20 #include "webrtc/engine_configurations.h" | |
21 #include "webrtc/modules/audio_coding/main/include/audio_coding_module.h" | |
22 #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs.
h" | |
23 #include "webrtc/modules/audio_coding/main/test/utility.h" | |
24 #include "webrtc/system_wrappers/include/trace.h" | |
25 #include "webrtc/test/testsupport/fileutils.h" | |
26 #include "webrtc/typedefs.h" | |
27 | |
28 // Description of the test: | |
29 // In this test we set up a one-way communication channel from a participant | |
30 // called "a" to a participant called "b". | |
31 // a -> channel_a_to_b -> b | |
32 // | |
33 // The test loops through all available mono codecs, encode at "a" sends over | |
34 // the channel, and decodes at "b". | |
35 | |
36 namespace { | |
37 const size_t kVariableSize = std::numeric_limits<size_t>::max(); | |
38 } | |
39 | |
40 namespace webrtc { | |
41 | |
42 // Class for simulating packet handling. | |
43 TestPack::TestPack() | |
44 : receiver_acm_(NULL), | |
45 sequence_number_(0), | |
46 timestamp_diff_(0), | |
47 last_in_timestamp_(0), | |
48 total_bytes_(0), | |
49 payload_size_(0) { | |
50 } | |
51 | |
52 TestPack::~TestPack() { | |
53 } | |
54 | |
55 void TestPack::RegisterReceiverACM(AudioCodingModule* acm) { | |
56 receiver_acm_ = acm; | |
57 return; | |
58 } | |
59 | |
60 int32_t TestPack::SendData(FrameType frame_type, uint8_t payload_type, | |
61 uint32_t timestamp, const uint8_t* payload_data, | |
62 size_t payload_size, | |
63 const RTPFragmentationHeader* fragmentation) { | |
64 WebRtcRTPHeader rtp_info; | |
65 int32_t status; | |
66 | |
67 rtp_info.header.markerBit = false; | |
68 rtp_info.header.ssrc = 0; | |
69 rtp_info.header.sequenceNumber = sequence_number_++; | |
70 rtp_info.header.payloadType = payload_type; | |
71 rtp_info.header.timestamp = timestamp; | |
72 if (frame_type == kAudioFrameCN) { | |
73 rtp_info.type.Audio.isCNG = true; | |
74 } else { | |
75 rtp_info.type.Audio.isCNG = false; | |
76 } | |
77 if (frame_type == kEmptyFrame) { | |
78 // Skip this frame. | |
79 return 0; | |
80 } | |
81 | |
82 // Only run mono for all test cases. | |
83 rtp_info.type.Audio.channel = 1; | |
84 memcpy(payload_data_, payload_data, payload_size); | |
85 | |
86 status = receiver_acm_->IncomingPacket(payload_data_, payload_size, rtp_info); | |
87 | |
88 payload_size_ = payload_size; | |
89 timestamp_diff_ = timestamp - last_in_timestamp_; | |
90 last_in_timestamp_ = timestamp; | |
91 total_bytes_ += payload_size; | |
92 return status; | |
93 } | |
94 | |
95 size_t TestPack::payload_size() { | |
96 return payload_size_; | |
97 } | |
98 | |
99 uint32_t TestPack::timestamp_diff() { | |
100 return timestamp_diff_; | |
101 } | |
102 | |
103 void TestPack::reset_payload_size() { | |
104 payload_size_ = 0; | |
105 } | |
106 | |
107 TestAllCodecs::TestAllCodecs(int test_mode) | |
108 : acm_a_(AudioCodingModule::Create(0)), | |
109 acm_b_(AudioCodingModule::Create(1)), | |
110 channel_a_to_b_(NULL), | |
111 test_count_(0), | |
112 packet_size_samples_(0), | |
113 packet_size_bytes_(0) { | |
114 // test_mode = 0 for silent test (auto test) | |
115 test_mode_ = test_mode; | |
116 } | |
117 | |
118 TestAllCodecs::~TestAllCodecs() { | |
119 if (channel_a_to_b_ != NULL) { | |
120 delete channel_a_to_b_; | |
121 channel_a_to_b_ = NULL; | |
122 } | |
123 } | |
124 | |
125 void TestAllCodecs::Perform() { | |
126 const std::string file_name = webrtc::test::ResourcePath( | |
127 "audio_coding/testfile32kHz", "pcm"); | |
128 infile_a_.Open(file_name, 32000, "rb"); | |
129 | |
130 if (test_mode_ == 0) { | |
131 WEBRTC_TRACE(kTraceStateInfo, kTraceAudioCoding, -1, | |
132 "---------- TestAllCodecs ----------"); | |
133 } | |
134 | |
135 acm_a_->InitializeReceiver(); | |
136 acm_b_->InitializeReceiver(); | |
137 | |
138 uint8_t num_encoders = acm_a_->NumberOfCodecs(); | |
139 CodecInst my_codec_param; | |
140 for (uint8_t n = 0; n < num_encoders; n++) { | |
141 acm_b_->Codec(n, &my_codec_param); | |
142 if (!strcmp(my_codec_param.plname, "opus")) { | |
143 my_codec_param.channels = 1; | |
144 } | |
145 acm_b_->RegisterReceiveCodec(my_codec_param); | |
146 } | |
147 | |
148 // Create and connect the channel | |
149 channel_a_to_b_ = new TestPack; | |
150 acm_a_->RegisterTransportCallback(channel_a_to_b_); | |
151 channel_a_to_b_->RegisterReceiverACM(acm_b_.get()); | |
152 | |
153 // All codecs are tested for all allowed sampling frequencies, rates and | |
154 // packet sizes. | |
155 #ifdef WEBRTC_CODEC_G722 | |
156 if (test_mode_ != 0) { | |
157 printf("===============================================================\n"); | |
158 } | |
159 test_count_++; | |
160 OpenOutFile(test_count_); | |
161 char codec_g722[] = "G722"; | |
162 RegisterSendCodec('A', codec_g722, 16000, 64000, 160, 0); | |
163 Run(channel_a_to_b_); | |
164 RegisterSendCodec('A', codec_g722, 16000, 64000, 320, 0); | |
165 Run(channel_a_to_b_); | |
166 RegisterSendCodec('A', codec_g722, 16000, 64000, 480, 0); | |
167 Run(channel_a_to_b_); | |
168 RegisterSendCodec('A', codec_g722, 16000, 64000, 640, 0); | |
169 Run(channel_a_to_b_); | |
170 RegisterSendCodec('A', codec_g722, 16000, 64000, 800, 0); | |
171 Run(channel_a_to_b_); | |
172 RegisterSendCodec('A', codec_g722, 16000, 64000, 960, 0); | |
173 Run(channel_a_to_b_); | |
174 outfile_b_.Close(); | |
175 #endif | |
176 #ifdef WEBRTC_CODEC_ILBC | |
177 if (test_mode_ != 0) { | |
178 printf("===============================================================\n"); | |
179 } | |
180 test_count_++; | |
181 OpenOutFile(test_count_); | |
182 char codec_ilbc[] = "ILBC"; | |
183 RegisterSendCodec('A', codec_ilbc, 8000, 13300, 240, 0); | |
184 Run(channel_a_to_b_); | |
185 RegisterSendCodec('A', codec_ilbc, 8000, 13300, 480, 0); | |
186 Run(channel_a_to_b_); | |
187 RegisterSendCodec('A', codec_ilbc, 8000, 15200, 160, 0); | |
188 Run(channel_a_to_b_); | |
189 RegisterSendCodec('A', codec_ilbc, 8000, 15200, 320, 0); | |
190 Run(channel_a_to_b_); | |
191 outfile_b_.Close(); | |
192 #endif | |
193 #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) | |
194 if (test_mode_ != 0) { | |
195 printf("===============================================================\n"); | |
196 } | |
197 test_count_++; | |
198 OpenOutFile(test_count_); | |
199 char codec_isac[] = "ISAC"; | |
200 RegisterSendCodec('A', codec_isac, 16000, -1, 480, kVariableSize); | |
201 Run(channel_a_to_b_); | |
202 RegisterSendCodec('A', codec_isac, 16000, -1, 960, kVariableSize); | |
203 Run(channel_a_to_b_); | |
204 RegisterSendCodec('A', codec_isac, 16000, 15000, 480, kVariableSize); | |
205 Run(channel_a_to_b_); | |
206 RegisterSendCodec('A', codec_isac, 16000, 32000, 960, kVariableSize); | |
207 Run(channel_a_to_b_); | |
208 outfile_b_.Close(); | |
209 #endif | |
210 #ifdef WEBRTC_CODEC_ISAC | |
211 if (test_mode_ != 0) { | |
212 printf("===============================================================\n"); | |
213 } | |
214 test_count_++; | |
215 OpenOutFile(test_count_); | |
216 RegisterSendCodec('A', codec_isac, 32000, -1, 960, kVariableSize); | |
217 Run(channel_a_to_b_); | |
218 RegisterSendCodec('A', codec_isac, 32000, 56000, 960, kVariableSize); | |
219 Run(channel_a_to_b_); | |
220 RegisterSendCodec('A', codec_isac, 32000, 37000, 960, kVariableSize); | |
221 Run(channel_a_to_b_); | |
222 RegisterSendCodec('A', codec_isac, 32000, 32000, 960, kVariableSize); | |
223 Run(channel_a_to_b_); | |
224 outfile_b_.Close(); | |
225 #endif | |
226 if (test_mode_ != 0) { | |
227 printf("===============================================================\n"); | |
228 } | |
229 test_count_++; | |
230 OpenOutFile(test_count_); | |
231 char codec_l16[] = "L16"; | |
232 RegisterSendCodec('A', codec_l16, 8000, 128000, 80, 0); | |
233 Run(channel_a_to_b_); | |
234 RegisterSendCodec('A', codec_l16, 8000, 128000, 160, 0); | |
235 Run(channel_a_to_b_); | |
236 RegisterSendCodec('A', codec_l16, 8000, 128000, 240, 0); | |
237 Run(channel_a_to_b_); | |
238 RegisterSendCodec('A', codec_l16, 8000, 128000, 320, 0); | |
239 Run(channel_a_to_b_); | |
240 outfile_b_.Close(); | |
241 if (test_mode_ != 0) { | |
242 printf("===============================================================\n"); | |
243 } | |
244 test_count_++; | |
245 OpenOutFile(test_count_); | |
246 RegisterSendCodec('A', codec_l16, 16000, 256000, 160, 0); | |
247 Run(channel_a_to_b_); | |
248 RegisterSendCodec('A', codec_l16, 16000, 256000, 320, 0); | |
249 Run(channel_a_to_b_); | |
250 RegisterSendCodec('A', codec_l16, 16000, 256000, 480, 0); | |
251 Run(channel_a_to_b_); | |
252 RegisterSendCodec('A', codec_l16, 16000, 256000, 640, 0); | |
253 Run(channel_a_to_b_); | |
254 outfile_b_.Close(); | |
255 if (test_mode_ != 0) { | |
256 printf("===============================================================\n"); | |
257 } | |
258 test_count_++; | |
259 OpenOutFile(test_count_); | |
260 RegisterSendCodec('A', codec_l16, 32000, 512000, 320, 0); | |
261 Run(channel_a_to_b_); | |
262 RegisterSendCodec('A', codec_l16, 32000, 512000, 640, 0); | |
263 Run(channel_a_to_b_); | |
264 outfile_b_.Close(); | |
265 if (test_mode_ != 0) { | |
266 printf("===============================================================\n"); | |
267 } | |
268 test_count_++; | |
269 OpenOutFile(test_count_); | |
270 char codec_pcma[] = "PCMA"; | |
271 RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, 0); | |
272 Run(channel_a_to_b_); | |
273 RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, 0); | |
274 Run(channel_a_to_b_); | |
275 RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, 0); | |
276 Run(channel_a_to_b_); | |
277 RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, 0); | |
278 Run(channel_a_to_b_); | |
279 RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, 0); | |
280 Run(channel_a_to_b_); | |
281 RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, 0); | |
282 Run(channel_a_to_b_); | |
283 if (test_mode_ != 0) { | |
284 printf("===============================================================\n"); | |
285 } | |
286 char codec_pcmu[] = "PCMU"; | |
287 RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, 0); | |
288 Run(channel_a_to_b_); | |
289 RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, 0); | |
290 Run(channel_a_to_b_); | |
291 RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, 0); | |
292 Run(channel_a_to_b_); | |
293 RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, 0); | |
294 Run(channel_a_to_b_); | |
295 RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, 0); | |
296 Run(channel_a_to_b_); | |
297 RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, 0); | |
298 Run(channel_a_to_b_); | |
299 outfile_b_.Close(); | |
300 #ifdef WEBRTC_CODEC_OPUS | |
301 if (test_mode_ != 0) { | |
302 printf("===============================================================\n"); | |
303 } | |
304 test_count_++; | |
305 OpenOutFile(test_count_); | |
306 char codec_opus[] = "OPUS"; | |
307 RegisterSendCodec('A', codec_opus, 48000, 6000, 480, kVariableSize); | |
308 Run(channel_a_to_b_); | |
309 RegisterSendCodec('A', codec_opus, 48000, 20000, 480*2, kVariableSize); | |
310 Run(channel_a_to_b_); | |
311 RegisterSendCodec('A', codec_opus, 48000, 32000, 480*4, kVariableSize); | |
312 Run(channel_a_to_b_); | |
313 RegisterSendCodec('A', codec_opus, 48000, 48000, 480, kVariableSize); | |
314 Run(channel_a_to_b_); | |
315 RegisterSendCodec('A', codec_opus, 48000, 64000, 480*4, kVariableSize); | |
316 Run(channel_a_to_b_); | |
317 RegisterSendCodec('A', codec_opus, 48000, 96000, 480*6, kVariableSize); | |
318 Run(channel_a_to_b_); | |
319 RegisterSendCodec('A', codec_opus, 48000, 500000, 480*2, kVariableSize); | |
320 Run(channel_a_to_b_); | |
321 outfile_b_.Close(); | |
322 #endif | |
323 if (test_mode_ != 0) { | |
324 printf("===============================================================\n"); | |
325 | |
326 /* Print out all codecs that were not tested in the run */ | |
327 printf("The following codecs was not included in the test:\n"); | |
328 #ifndef WEBRTC_CODEC_G722 | |
329 printf(" G.722\n"); | |
330 #endif | |
331 #ifndef WEBRTC_CODEC_ILBC | |
332 printf(" iLBC\n"); | |
333 #endif | |
334 #ifndef WEBRTC_CODEC_ISAC | |
335 printf(" ISAC float\n"); | |
336 #endif | |
337 #ifndef WEBRTC_CODEC_ISACFX | |
338 printf(" ISAC fix\n"); | |
339 #endif | |
340 | |
341 printf("\nTo complete the test, listen to the %d number of output files.\n", | |
342 test_count_); | |
343 } | |
344 } | |
345 | |
346 // Register Codec to use in the test | |
347 // | |
348 // Input: side - which ACM to use, 'A' or 'B' | |
349 // codec_name - name to use when register the codec | |
350 // sampling_freq_hz - sampling frequency in Herz | |
351 // rate - bitrate in bytes | |
352 // packet_size - packet size in samples | |
353 // extra_byte - if extra bytes needed compared to the bitrate | |
354 // used when registering, can be an internal header | |
355 // set to kVariableSize if the codec is a variable | |
356 // rate codec | |
357 void TestAllCodecs::RegisterSendCodec(char side, char* codec_name, | |
358 int32_t sampling_freq_hz, int rate, | |
359 int packet_size, size_t extra_byte) { | |
360 if (test_mode_ != 0) { | |
361 // Print out codec and settings. | |
362 printf("codec: %s Freq: %d Rate: %d PackSize: %d\n", codec_name, | |
363 sampling_freq_hz, rate, packet_size); | |
364 } | |
365 | |
366 // Store packet-size in samples, used to validate the received packet. | |
367 // If G.722, store half the size to compensate for the timestamp bug in the | |
368 // RFC for G.722. | |
369 // If iSAC runs in adaptive mode, packet size in samples can change on the | |
370 // fly, so we exclude this test by setting |packet_size_samples_| to -1. | |
371 if (!strcmp(codec_name, "G722")) { | |
372 packet_size_samples_ = packet_size / 2; | |
373 } else if (!strcmp(codec_name, "ISAC") && (rate == -1)) { | |
374 packet_size_samples_ = -1; | |
375 } else { | |
376 packet_size_samples_ = packet_size; | |
377 } | |
378 | |
379 // Store the expected packet size in bytes, used to validate the received | |
380 // packet. If variable rate codec (extra_byte == -1), set to -1. | |
381 if (extra_byte != kVariableSize) { | |
382 // Add 0.875 to always round up to a whole byte | |
383 packet_size_bytes_ = static_cast<size_t>( | |
384 static_cast<float>(packet_size * rate) / | |
385 static_cast<float>(sampling_freq_hz * 8) + 0.875) + extra_byte; | |
386 } else { | |
387 // Packets will have a variable size. | |
388 packet_size_bytes_ = kVariableSize; | |
389 } | |
390 | |
391 // Set pointer to the ACM where to register the codec. | |
392 AudioCodingModule* my_acm = NULL; | |
393 switch (side) { | |
394 case 'A': { | |
395 my_acm = acm_a_.get(); | |
396 break; | |
397 } | |
398 case 'B': { | |
399 my_acm = acm_b_.get(); | |
400 break; | |
401 } | |
402 default: { | |
403 break; | |
404 } | |
405 } | |
406 ASSERT_TRUE(my_acm != NULL); | |
407 | |
408 // Get all codec parameters before registering | |
409 CodecInst my_codec_param; | |
410 CHECK_ERROR(AudioCodingModule::Codec(codec_name, &my_codec_param, | |
411 sampling_freq_hz, 1)); | |
412 my_codec_param.rate = rate; | |
413 my_codec_param.pacsize = packet_size; | |
414 CHECK_ERROR(my_acm->RegisterSendCodec(my_codec_param)); | |
415 } | |
416 | |
417 void TestAllCodecs::Run(TestPack* channel) { | |
418 AudioFrame audio_frame; | |
419 | |
420 int32_t out_freq_hz = outfile_b_.SamplingFrequency(); | |
421 size_t receive_size; | |
422 uint32_t timestamp_diff; | |
423 channel->reset_payload_size(); | |
424 int error_count = 0; | |
425 | |
426 int counter = 0; | |
427 while (!infile_a_.EndOfFile()) { | |
428 // Add 10 msec to ACM. | |
429 infile_a_.Read10MsData(audio_frame); | |
430 CHECK_ERROR(acm_a_->Add10MsData(audio_frame)); | |
431 | |
432 // Verify that the received packet size matches the settings. | |
433 receive_size = channel->payload_size(); | |
434 if (receive_size) { | |
435 if ((receive_size != packet_size_bytes_) && | |
436 (packet_size_bytes_ != kVariableSize)) { | |
437 error_count++; | |
438 } | |
439 | |
440 // Verify that the timestamp is updated with expected length. The counter | |
441 // is used to avoid problems when switching codec or frame size in the | |
442 // test. | |
443 timestamp_diff = channel->timestamp_diff(); | |
444 if ((counter > 10) && | |
445 (static_cast<int>(timestamp_diff) != packet_size_samples_) && | |
446 (packet_size_samples_ > -1)) | |
447 error_count++; | |
448 } | |
449 | |
450 // Run received side of ACM. | |
451 CHECK_ERROR(acm_b_->PlayoutData10Ms(out_freq_hz, &audio_frame)); | |
452 | |
453 // Write output speech to file. | |
454 outfile_b_.Write10MsData(audio_frame.data_, | |
455 audio_frame.samples_per_channel_); | |
456 | |
457 // Update loop counter | |
458 counter++; | |
459 } | |
460 | |
461 EXPECT_EQ(0, error_count); | |
462 | |
463 if (infile_a_.EndOfFile()) { | |
464 infile_a_.Rewind(); | |
465 } | |
466 } | |
467 | |
468 void TestAllCodecs::OpenOutFile(int test_number) { | |
469 std::string filename = webrtc::test::OutputPath(); | |
470 std::ostringstream test_number_str; | |
471 test_number_str << test_number; | |
472 filename += "testallcodecs_out_"; | |
473 filename += test_number_str.str(); | |
474 filename += ".pcm"; | |
475 outfile_b_.Open(filename, 32000, "wb"); | |
476 } | |
477 | |
478 void TestAllCodecs::DisplaySendReceiveCodec() { | |
479 CodecInst my_codec_param; | |
480 printf("%s -> ", acm_a_->SendCodec()->plname); | |
481 acm_b_->ReceiveCodec(&my_codec_param); | |
482 printf("%s\n", my_codec_param.plname); | |
483 } | |
484 | |
485 } // namespace webrtc | |
OLD | NEW |