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/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/include/audio_coding_module.h" 22 #include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h" 23 #include "webrtc/modules/audio_coding/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 int counter = 0; 426 // Set test length to 500 ms (50 blocks of 10 ms each). 427 infile_a_.SetNum10MsBlocksToRead(50); 428 // Fast-forward 1 second (100 blocks) since the file starts with silence. 429 infile_a_.FastForward(100); 430 431 while (!infile_a_.EndOfFile()) { 432 // Add 10 msec to ACM. 433 infile_a_.Read10MsData(audio_frame); 434 CHECK_ERROR(acm_a_->Add10MsData(audio_frame)); 435 436 // Verify that the received packet size matches the settings. 437 receive_size = channel->payload_size(); 438 if (receive_size) { 439 if ((receive_size != packet_size_bytes_) && 440 (packet_size_bytes_ != kVariableSize)) { 441 error_count++; 442 } 443 444 // Verify that the timestamp is updated with expected length. The counter 445 // is used to avoid problems when switching codec or frame size in the 446 // test. 447 timestamp_diff = channel->timestamp_diff(); 448 if ((counter > 10) && 449 (static_cast<int>(timestamp_diff) != packet_size_samples_) && 450 (packet_size_samples_ > -1)) 451 error_count++; 452 } 453 454 // Run received side of ACM. 455 CHECK_ERROR(acm_b_->PlayoutData10Ms(out_freq_hz, &audio_frame)); 456 457 // Write output speech to file. 458 outfile_b_.Write10MsData(audio_frame.data_, 459 audio_frame.samples_per_channel_); 460 461 // Update loop counter 462 counter++; 463 } 464 465 EXPECT_EQ(0, error_count); 466 467 if (infile_a_.EndOfFile()) { 468 infile_a_.Rewind(); 469 } 470 } 471 472 void TestAllCodecs::OpenOutFile(int test_number) { 473 std::string filename = webrtc::test::OutputPath(); 474 std::ostringstream test_number_str; 475 test_number_str << test_number; 476 filename += "testallcodecs_out_"; 477 filename += test_number_str.str(); 478 filename += ".pcm"; 479 outfile_b_.Open(filename, 32000, "wb"); 480 } 481 482 void TestAllCodecs::DisplaySendReceiveCodec() { 483 CodecInst my_codec_param; 484 printf("%s -> ", acm_a_->SendCodec()->plname); 485 acm_b_->ReceiveCodec(&my_codec_param); 486 printf("%s\n", my_codec_param.plname); 487 } 488 489 } // namespace webrtc 490