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 <stdio.h>
12#include <string.h>
13
14#include <math.h>
15
16#include "webrtc/common_types.h"
17#include "webrtc/modules/audio_coding/test/SpatialAudio.h"
18#include "webrtc/system_wrappers/include/trace.h"
19#include "webrtc/system_wrappers/include/trace.h"
20#include "webrtc/test/testsupport/fileutils.h"
21
22namespace webrtc {
23
24#define NUM_PANN_COEFFS 10
25
26SpatialAudio::SpatialAudio(int testMode)
27    : _acmLeft(AudioCodingModule::Create(1)),
28      _acmRight(AudioCodingModule::Create(2)),
29      _acmReceiver(AudioCodingModule::Create(3)),
30      _testMode(testMode) {
31}
32
33SpatialAudio::~SpatialAudio() {
34  delete _channel;
35  _inFile.Close();
36  _outFile.Close();
37}
38
39int16_t SpatialAudio::Setup() {
40  _channel = new Channel;
41
42  // Register callback for the sender side.
43  CHECK_ERROR(_acmLeft->RegisterTransportCallback(_channel));
44  CHECK_ERROR(_acmRight->RegisterTransportCallback(_channel));
45  // Register the receiver ACM in channel
46  _channel->RegisterReceiverACM(_acmReceiver.get());
47
48  uint16_t sampFreqHz = 32000;
49
50  const std::string file_name = webrtc::test::ResourcePath(
51      "audio_coding/testfile32kHz", "pcm");
52  _inFile.Open(file_name, sampFreqHz, "rb", false);
53
54  std::string output_file = webrtc::test::OutputPath()
55      + "out_spatial_autotest.pcm";
56  if (_testMode == 1) {
57    output_file = webrtc::test::OutputPath() + "testspatial_out.pcm";
58    printf("\n");
59    printf("Enter the output file [%s]: ", output_file.c_str());
60    PCMFile::ChooseFile(&output_file, MAX_FILE_NAME_LENGTH_BYTE, &sampFreqHz);
61  } else {
62    output_file = webrtc::test::OutputPath() + "testspatial_out.pcm";
63  }
64  _outFile.Open(output_file, sampFreqHz, "wb", false);
65  _outFile.SaveStereo(true);
66
67  // Register all available codes as receiving codecs.
68  CodecInst codecInst;
69  int status;
70  uint8_t num_encoders = _acmReceiver->NumberOfCodecs();
71  // Register all available codes as receiving codecs once more.
72  for (uint8_t n = 0; n < num_encoders; n++) {
73    status = _acmReceiver->Codec(n, &codecInst);
74    if (status < 0) {
75      printf("Error in Codec(), no matching codec found");
76    }
77    status = _acmReceiver->RegisterReceiveCodec(codecInst);
78    if (status < 0) {
79      printf("Error in RegisterReceiveCodec() for payload type %d",
80             codecInst.pltype);
81    }
82  }
83
84  return 0;
85}
86
87void SpatialAudio::Perform() {
88  if (_testMode == 0) {
89    printf("Running SpatialAudio Test");
90    WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceAudioCoding, -1,
91                 "---------- SpatialAudio ----------");
92  }
93
94  Setup();
95
96  CodecInst codecInst;
97  _acmLeft->Codec((uint8_t) 1, &codecInst);
98  CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
99  EncodeDecode();
100
101  int16_t pannCntr = 0;
102
103  double leftPanning[NUM_PANN_COEFFS] = { 1.00, 0.95, 0.90, 0.85, 0.80, 0.75,
104      0.70, 0.60, 0.55, 0.50 };
105  double rightPanning[NUM_PANN_COEFFS] = { 0.50, 0.55, 0.60, 0.70, 0.75, 0.80,
106      0.85, 0.90, 0.95, 1.00 };
107
108  while ((pannCntr + 1) < NUM_PANN_COEFFS) {
109    _acmLeft->Codec((uint8_t) 0, &codecInst);
110    codecInst.pacsize = 480;
111    CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
112    CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
113
114    EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
115    pannCntr++;
116
117    // Change codec
118    _acmLeft->Codec((uint8_t) 3, &codecInst);
119    codecInst.pacsize = 320;
120    CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
121    CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
122
123    EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
124    pannCntr++;
125    if (_testMode == 0) {
126      printf(".");
127    }
128  }
129
130  _acmLeft->Codec((uint8_t) 4, &codecInst);
131  CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
132  EncodeDecode();
133
134  _acmLeft->Codec((uint8_t) 0, &codecInst);
135  codecInst.pacsize = 480;
136  CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
137  CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
138  pannCntr = NUM_PANN_COEFFS - 1;
139  while (pannCntr >= 0) {
140    EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
141    pannCntr--;
142    if (_testMode == 0) {
143      printf(".");
144    }
145  }
146  if (_testMode == 0) {
147    printf("Done!\n");
148  }
149}
150
151void SpatialAudio::EncodeDecode(const double leftPanning,
152                                const double rightPanning) {
153  AudioFrame audioFrame;
154  int32_t outFileSampFreq = _outFile.SamplingFrequency();
155
156  const double rightToLeftRatio = rightPanning / leftPanning;
157
158  _channel->SetIsStereo(true);
159
160  while (!_inFile.EndOfFile()) {
161    _inFile.Read10MsData(audioFrame);
162    for (size_t n = 0; n < audioFrame.samples_per_channel_; n++) {
163      audioFrame.data_[n] = (int16_t) floor(
164          audioFrame.data_[n] * leftPanning + 0.5);
165    }
166    CHECK_ERROR(_acmLeft->Add10MsData(audioFrame));
167
168    for (size_t n = 0; n < audioFrame.samples_per_channel_; n++) {
169      audioFrame.data_[n] = (int16_t) floor(
170          audioFrame.data_[n] * rightToLeftRatio + 0.5);
171    }
172    CHECK_ERROR(_acmRight->Add10MsData(audioFrame));
173
174    CHECK_ERROR(_acmReceiver->PlayoutData10Ms(outFileSampFreq, &audioFrame));
175    _outFile.Write10MsData(audioFrame);
176  }
177  _inFile.Rewind();
178}
179
180void SpatialAudio::EncodeDecode() {
181  AudioFrame audioFrame;
182  int32_t outFileSampFreq = _outFile.SamplingFrequency();
183
184  _channel->SetIsStereo(false);
185
186  while (!_inFile.EndOfFile()) {
187    _inFile.Read10MsData(audioFrame);
188    CHECK_ERROR(_acmLeft->Add10MsData(audioFrame));
189
190    CHECK_ERROR(_acmReceiver->PlayoutData10Ms(outFileSampFreq, &audioFrame));
191    _outFile.Write10MsData(audioFrame);
192  }
193  _inFile.Rewind();
194}
195
196}  // namespace webrtc
197