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