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