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/EncodeDecodeTest.h"
     12 
     13 #include <sstream>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "webrtc/base/scoped_ptr.h"
     19 #include "webrtc/common_types.h"
     20 #include "webrtc/modules/audio_coding/include/audio_coding_module.h"
     21 #include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
     22 #include "webrtc/modules/audio_coding/test/utility.h"
     23 #include "webrtc/system_wrappers/include/trace.h"
     24 #include "webrtc/test/testsupport/fileutils.h"
     25 
     26 namespace webrtc {
     27 
     28 TestPacketization::TestPacketization(RTPStream *rtpStream, uint16_t frequency)
     29     : _rtpStream(rtpStream),
     30       _frequency(frequency),
     31       _seqNo(0) {
     32 }
     33 
     34 TestPacketization::~TestPacketization() {
     35 }
     36 
     37 int32_t TestPacketization::SendData(
     38     const FrameType /* frameType */, const uint8_t payloadType,
     39     const uint32_t timeStamp, const uint8_t* payloadData,
     40     const size_t payloadSize,
     41     const RTPFragmentationHeader* /* fragmentation */) {
     42   _rtpStream->Write(payloadType, timeStamp, _seqNo++, payloadData, payloadSize,
     43                     _frequency);
     44   return 1;
     45 }
     46 
     47 Sender::Sender()
     48     : _acm(NULL),
     49       _pcmFile(),
     50       _audioFrame(),
     51       _packetization(NULL) {
     52 }
     53 
     54 void Sender::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
     55                    std::string in_file_name, int sample_rate, size_t channels) {
     56   struct CodecInst sendCodec;
     57   int noOfCodecs = acm->NumberOfCodecs();
     58   int codecNo;
     59 
     60   // Open input file
     61   const std::string file_name = webrtc::test::ResourcePath(in_file_name, "pcm");
     62   _pcmFile.Open(file_name, sample_rate, "rb");
     63   if (channels == 2) {
     64     _pcmFile.ReadStereo(true);
     65   }
     66   // Set test length to 500 ms (50 blocks of 10 ms each).
     67   _pcmFile.SetNum10MsBlocksToRead(50);
     68   // Fast-forward 1 second (100 blocks) since the file starts with silence.
     69   _pcmFile.FastForward(100);
     70 
     71   // Set the codec for the current test.
     72   if ((testMode == 0) || (testMode == 1)) {
     73     // Set the codec id.
     74     codecNo = codeId;
     75   } else {
     76     // Choose codec on command line.
     77     printf("List of supported codec.\n");
     78     for (int n = 0; n < noOfCodecs; n++) {
     79       EXPECT_EQ(0, acm->Codec(n, &sendCodec));
     80       printf("%d %s\n", n, sendCodec.plname);
     81     }
     82     printf("Choose your codec:");
     83     ASSERT_GT(scanf("%d", &codecNo), 0);
     84   }
     85 
     86   EXPECT_EQ(0, acm->Codec(codecNo, &sendCodec));
     87 
     88   sendCodec.channels = channels;
     89 
     90   EXPECT_EQ(0, acm->RegisterSendCodec(sendCodec));
     91   _packetization = new TestPacketization(rtpStream, sendCodec.plfreq);
     92   EXPECT_EQ(0, acm->RegisterTransportCallback(_packetization));
     93 
     94   _acm = acm;
     95 }
     96 
     97 void Sender::Teardown() {
     98   _pcmFile.Close();
     99   delete _packetization;
    100 }
    101 
    102 bool Sender::Add10MsData() {
    103   if (!_pcmFile.EndOfFile()) {
    104     EXPECT_GT(_pcmFile.Read10MsData(_audioFrame), 0);
    105     int32_t ok = _acm->Add10MsData(_audioFrame);
    106     EXPECT_GE(ok, 0);
    107     return ok >= 0 ? true : false;
    108   }
    109   return false;
    110 }
    111 
    112 void Sender::Run() {
    113   while (true) {
    114     if (!Add10MsData()) {
    115       break;
    116     }
    117   }
    118 }
    119 
    120 Receiver::Receiver()
    121     : _playoutLengthSmpls(WEBRTC_10MS_PCM_AUDIO),
    122       _payloadSizeBytes(MAX_INCOMING_PAYLOAD) {
    123 }
    124 
    125 void Receiver::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
    126                      std::string out_file_name, size_t channels) {
    127   struct CodecInst recvCodec = CodecInst();
    128   int noOfCodecs;
    129   EXPECT_EQ(0, acm->InitializeReceiver());
    130 
    131   noOfCodecs = acm->NumberOfCodecs();
    132   for (int i = 0; i < noOfCodecs; i++) {
    133     EXPECT_EQ(0, acm->Codec(i, &recvCodec));
    134     if (recvCodec.channels == channels)
    135       EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
    136     // Forces mono/stereo for Opus.
    137     if (!strcmp(recvCodec.plname, "opus")) {
    138       recvCodec.channels = channels;
    139       EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
    140     }
    141   }
    142 
    143   int playSampFreq;
    144   std::string file_name;
    145   std::stringstream file_stream;
    146   file_stream << webrtc::test::OutputPath() << out_file_name
    147       << static_cast<int>(codeId) << ".pcm";
    148   file_name = file_stream.str();
    149   _rtpStream = rtpStream;
    150 
    151   if (testMode == 1) {
    152     playSampFreq = recvCodec.plfreq;
    153     _pcmFile.Open(file_name, recvCodec.plfreq, "wb+");
    154   } else if (testMode == 0) {
    155     playSampFreq = 32000;
    156     _pcmFile.Open(file_name, 32000, "wb+");
    157   } else {
    158     printf("\nValid output frequencies:\n");
    159     printf("8000\n16000\n32000\n-1,");
    160     printf("which means output frequency equal to received signal frequency");
    161     printf("\n\nChoose output sampling frequency: ");
    162     ASSERT_GT(scanf("%d", &playSampFreq), 0);
    163     file_name = webrtc::test::OutputPath() + out_file_name + ".pcm";
    164     _pcmFile.Open(file_name, playSampFreq, "wb+");
    165   }
    166 
    167   _realPayloadSizeBytes = 0;
    168   _playoutBuffer = new int16_t[WEBRTC_10MS_PCM_AUDIO];
    169   _frequency = playSampFreq;
    170   _acm = acm;
    171   _firstTime = true;
    172 }
    173 
    174 void Receiver::Teardown() {
    175   delete[] _playoutBuffer;
    176   _pcmFile.Close();
    177   if (testMode > 1) {
    178     Trace::ReturnTrace();
    179   }
    180 }
    181 
    182 bool Receiver::IncomingPacket() {
    183   if (!_rtpStream->EndOfFile()) {
    184     if (_firstTime) {
    185       _firstTime = false;
    186       _realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
    187                                                _payloadSizeBytes, &_nextTime);
    188       if (_realPayloadSizeBytes == 0) {
    189         if (_rtpStream->EndOfFile()) {
    190           _firstTime = true;
    191           return true;
    192         } else {
    193           return false;
    194         }
    195       }
    196     }
    197 
    198     EXPECT_EQ(0, _acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes,
    199                                       _rtpInfo));
    200     _realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
    201                                              _payloadSizeBytes, &_nextTime);
    202     if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
    203       _firstTime = true;
    204     }
    205   }
    206   return true;
    207 }
    208 
    209 bool Receiver::PlayoutData() {
    210   AudioFrame audioFrame;
    211 
    212   int32_t ok =_acm->PlayoutData10Ms(_frequency, &audioFrame);
    213   EXPECT_EQ(0, ok);
    214   if (ok < 0){
    215     return false;
    216   }
    217   if (_playoutLengthSmpls == 0) {
    218     return false;
    219   }
    220   _pcmFile.Write10MsData(audioFrame.data_,
    221       audioFrame.samples_per_channel_ * audioFrame.num_channels_);
    222   return true;
    223 }
    224 
    225 void Receiver::Run() {
    226   uint8_t counter500Ms = 50;
    227   uint32_t clock = 0;
    228 
    229   while (counter500Ms > 0) {
    230     if (clock == 0 || clock >= _nextTime) {
    231       EXPECT_TRUE(IncomingPacket());
    232       if (clock == 0) {
    233         clock = _nextTime;
    234       }
    235     }
    236     if ((clock % 10) == 0) {
    237       if (!PlayoutData()) {
    238         clock++;
    239         continue;
    240       }
    241     }
    242     if (_rtpStream->EndOfFile()) {
    243       counter500Ms--;
    244     }
    245     clock++;
    246   }
    247 }
    248 
    249 EncodeDecodeTest::EncodeDecodeTest() {
    250   _testMode = 2;
    251   Trace::CreateTrace();
    252   Trace::SetTraceFile(
    253       (webrtc::test::OutputPath() + "acm_encdec_trace.txt").c_str());
    254 }
    255 
    256 EncodeDecodeTest::EncodeDecodeTest(int testMode) {
    257   //testMode == 0 for autotest
    258   //testMode == 1 for testing all codecs/parameters
    259   //testMode > 1 for specific user-input test (as it was used before)
    260   _testMode = testMode;
    261   if (_testMode != 0) {
    262     Trace::CreateTrace();
    263     Trace::SetTraceFile(
    264         (webrtc::test::OutputPath() + "acm_encdec_trace.txt").c_str());
    265   }
    266 }
    267 
    268 void EncodeDecodeTest::Perform() {
    269   int numCodecs = 1;
    270   int codePars[3];  // Frequency, packet size, rate.
    271   int numPars[52];  // Number of codec parameters sets (freq, pacsize, rate)
    272                     // to test, for a given codec.
    273 
    274   codePars[0] = 0;
    275   codePars[1] = 0;
    276   codePars[2] = 0;
    277 
    278   rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(0));
    279   struct CodecInst sendCodecTmp;
    280   numCodecs = acm->NumberOfCodecs();
    281 
    282   if (_testMode != 2) {
    283     for (int n = 0; n < numCodecs; n++) {
    284       EXPECT_EQ(0, acm->Codec(n, &sendCodecTmp));
    285       if (STR_CASE_CMP(sendCodecTmp.plname, "telephone-event") == 0) {
    286         numPars[n] = 0;
    287       } else if (STR_CASE_CMP(sendCodecTmp.plname, "cn") == 0) {
    288         numPars[n] = 0;
    289       } else if (STR_CASE_CMP(sendCodecTmp.plname, "red") == 0) {
    290         numPars[n] = 0;
    291       } else if (sendCodecTmp.channels == 2) {
    292         numPars[n] = 0;
    293       } else {
    294         numPars[n] = 1;
    295       }
    296     }
    297   } else {
    298     numCodecs = 1;
    299     numPars[0] = 1;
    300   }
    301 
    302   _receiver.testMode = _testMode;
    303 
    304   // Loop over all mono codecs:
    305   for (int codeId = 0; codeId < numCodecs; codeId++) {
    306     // Only encode using real mono encoders, not telephone-event and cng.
    307     for (int loopPars = 1; loopPars <= numPars[codeId]; loopPars++) {
    308       // Encode all data to file.
    309       std::string fileName = EncodeToFile(1, codeId, codePars, _testMode);
    310 
    311       RTPFile rtpFile;
    312       rtpFile.Open(fileName.c_str(), "rb");
    313 
    314       _receiver.codeId = codeId;
    315 
    316       rtpFile.ReadHeader();
    317       _receiver.Setup(acm.get(), &rtpFile, "encodeDecode_out", 1);
    318       _receiver.Run();
    319       _receiver.Teardown();
    320       rtpFile.Close();
    321     }
    322   }
    323 
    324   // End tracing.
    325   if (_testMode == 1) {
    326     Trace::ReturnTrace();
    327   }
    328 }
    329 
    330 std::string EncodeDecodeTest::EncodeToFile(int fileType,
    331                                            int codeId,
    332                                            int* codePars,
    333                                            int testMode) {
    334   rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(1));
    335   RTPFile rtpFile;
    336   std::string fileName = webrtc::test::TempFilename(webrtc::test::OutputPath(),
    337                                                     "encode_decode_rtp");
    338   rtpFile.Open(fileName.c_str(), "wb+");
    339   rtpFile.WriteHeader();
    340 
    341   // Store for auto_test and logging.
    342   _sender.testMode = testMode;
    343   _sender.codeId = codeId;
    344 
    345   _sender.Setup(acm.get(), &rtpFile, "audio_coding/testfile32kHz", 32000, 1);
    346   if (acm->SendCodec()) {
    347     _sender.Run();
    348   }
    349   _sender.Teardown();
    350   rtpFile.Close();
    351 
    352   return fileName;
    353 }
    354 
    355 }  // namespace webrtc
    356