Home | History | Annotate | Download | only in test
      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