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 "TwoWayCommunication.h"
12 
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include <memory>
18 
19 #ifdef WIN32
20 #include <Windows.h>
21 #endif
22 
23 #include "webrtc/common_types.h"
24 #include "webrtc/modules/audio_coding/codecs/audio_format_conversion.h"
25 #include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
26 #include "webrtc/modules/audio_coding/test/PCMFile.h"
27 #include "webrtc/modules/audio_coding/test/utility.h"
28 #include "webrtc/system_wrappers/include/trace.h"
29 #include "webrtc/test/gtest.h"
30 #include "webrtc/test/testsupport/fileutils.h"
31 #include "webrtc/typedefs.h"
32 
33 namespace webrtc {
34 
35 #define MAX_FILE_NAME_LENGTH_BYTE 500
36 
TwoWayCommunication(int testMode)37 TwoWayCommunication::TwoWayCommunication(int testMode)
38     : _acmA(AudioCodingModule::Create(1)),
39       _acmRefA(AudioCodingModule::Create(3)),
40       _testMode(testMode) {
41   AudioCodingModule::Config config;
42   // The clicks will be more obvious in FAX mode. TODO(henrik.lundin) Really?
43   config.neteq_config.playout_mode = kPlayoutFax;
44   config.id = 2;
45   config.decoder_factory = CreateBuiltinAudioDecoderFactory();
46   _acmB.reset(AudioCodingModule::Create(config));
47   config.id = 4;
48   _acmRefB.reset(AudioCodingModule::Create(config));
49 }
50 
~TwoWayCommunication()51 TwoWayCommunication::~TwoWayCommunication() {
52   delete _channel_A2B;
53   delete _channel_B2A;
54   delete _channelRef_A2B;
55   delete _channelRef_B2A;
56   _inFileA.Close();
57   _inFileB.Close();
58   _outFileA.Close();
59   _outFileB.Close();
60   _outFileRefA.Close();
61   _outFileRefB.Close();
62 }
63 
ChooseCodec(uint8_t * codecID_A,uint8_t * codecID_B)64 void TwoWayCommunication::ChooseCodec(uint8_t* codecID_A,
65                                       uint8_t* codecID_B) {
66   std::unique_ptr<AudioCodingModule> tmpACM(AudioCodingModule::Create(0));
67   uint8_t noCodec = tmpACM->NumberOfCodecs();
68   CodecInst codecInst;
69   printf("List of Supported Codecs\n");
70   printf("========================\n");
71   for (uint8_t codecCntr = 0; codecCntr < noCodec; codecCntr++) {
72     EXPECT_EQ(tmpACM->Codec(codecCntr, &codecInst), 0);
73     printf("%d- %s\n", codecCntr, codecInst.plname);
74   }
75   printf("\nChoose a send codec for side A [0]: ");
76   char myStr[15] = "";
77   EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
78   *codecID_A = (uint8_t) atoi(myStr);
79 
80   printf("\nChoose a send codec for side B [0]: ");
81   EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
82   *codecID_B = (uint8_t) atoi(myStr);
83 
84   printf("\n");
85 }
86 
SetUp()87 void TwoWayCommunication::SetUp() {
88   uint8_t codecID_A;
89   uint8_t codecID_B;
90 
91   ChooseCodec(&codecID_A, &codecID_B);
92   CodecInst codecInst_A;
93   CodecInst codecInst_B;
94   CodecInst dummyCodec;
95   EXPECT_EQ(0, _acmA->Codec(codecID_A, &codecInst_A));
96   EXPECT_EQ(0, _acmB->Codec(codecID_B, &codecInst_B));
97   EXPECT_EQ(0, _acmA->Codec(6, &dummyCodec));
98 
99   //--- Set A codecs
100   EXPECT_EQ(0, _acmA->RegisterSendCodec(codecInst_A));
101   EXPECT_EQ(true, _acmA->RegisterReceiveCodec(codecInst_B.pltype,
102                                               CodecInstToSdp(codecInst_B)));
103   //--- Set ref-A codecs
104   EXPECT_EQ(0, _acmRefA->RegisterSendCodec(codecInst_A));
105   EXPECT_EQ(true, _acmRefA->RegisterReceiveCodec(codecInst_B.pltype,
106                                                  CodecInstToSdp(codecInst_B)));
107 
108   //--- Set B codecs
109   EXPECT_EQ(0, _acmB->RegisterSendCodec(codecInst_B));
110   EXPECT_EQ(true, _acmB->RegisterReceiveCodec(codecInst_A.pltype,
111                                               CodecInstToSdp(codecInst_A)));
112 
113   //--- Set ref-B codecs
114   EXPECT_EQ(0, _acmRefB->RegisterSendCodec(codecInst_B));
115   EXPECT_EQ(true, _acmRefB->RegisterReceiveCodec(codecInst_A.pltype,
116                                                  CodecInstToSdp(codecInst_A)));
117 
118   uint16_t frequencyHz;
119 
120   //--- Input A
121   std::string in_file_name = webrtc::test::ResourcePath(
122       "audio_coding/testfile32kHz", "pcm");
123   frequencyHz = 32000;
124   printf("Enter input file at side A [%s]: ", in_file_name.c_str());
125   PCMFile::ChooseFile(&in_file_name, 499, &frequencyHz);
126   _inFileA.Open(in_file_name, frequencyHz, "rb");
127 
128   //--- Output A
129   std::string out_file_a = webrtc::test::OutputPath() + "outA.pcm";
130   printf("Output file at side A: %s\n", out_file_a.c_str());
131   printf("Sampling frequency (in Hz) of the above file: %u\n", frequencyHz);
132   _outFileA.Open(out_file_a, frequencyHz, "wb");
133   std::string ref_file_name = webrtc::test::OutputPath() + "ref_outA.pcm";
134   _outFileRefA.Open(ref_file_name, frequencyHz, "wb");
135 
136   //--- Input B
137   in_file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz",
138                                             "pcm");
139   frequencyHz = 32000;
140   printf("\n\nEnter input file at side B [%s]: ", in_file_name.c_str());
141   PCMFile::ChooseFile(&in_file_name, 499, &frequencyHz);
142   _inFileB.Open(in_file_name, frequencyHz, "rb");
143 
144   //--- Output B
145   std::string out_file_b = webrtc::test::OutputPath() + "outB.pcm";
146   printf("Output file at side B: %s\n", out_file_b.c_str());
147   printf("Sampling frequency (in Hz) of the above file: %u\n", frequencyHz);
148   _outFileB.Open(out_file_b, frequencyHz, "wb");
149   ref_file_name = webrtc::test::OutputPath() + "ref_outB.pcm";
150   _outFileRefB.Open(ref_file_name, frequencyHz, "wb");
151 
152   //--- Set A-to-B channel
153   _channel_A2B = new Channel;
154   _acmA->RegisterTransportCallback(_channel_A2B);
155   _channel_A2B->RegisterReceiverACM(_acmB.get());
156   //--- Do the same for the reference
157   _channelRef_A2B = new Channel;
158   _acmRefA->RegisterTransportCallback(_channelRef_A2B);
159   _channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
160 
161   //--- Set B-to-A channel
162   _channel_B2A = new Channel;
163   _acmB->RegisterTransportCallback(_channel_B2A);
164   _channel_B2A->RegisterReceiverACM(_acmA.get());
165   //--- Do the same for reference
166   _channelRef_B2A = new Channel;
167   _acmRefB->RegisterTransportCallback(_channelRef_B2A);
168   _channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
169 }
170 
SetUpAutotest()171 void TwoWayCommunication::SetUpAutotest() {
172   CodecInst codecInst_A;
173   CodecInst codecInst_B;
174   CodecInst dummyCodec;
175 
176   EXPECT_EQ(0, _acmA->Codec("ISAC", &codecInst_A, 16000, 1));
177   EXPECT_EQ(0, _acmB->Codec("L16", &codecInst_B, 8000, 1));
178   EXPECT_EQ(0, _acmA->Codec(6, &dummyCodec));
179 
180   //--- Set A codecs
181   EXPECT_EQ(0, _acmA->RegisterSendCodec(codecInst_A));
182   EXPECT_EQ(true, _acmA->RegisterReceiveCodec(codecInst_B.pltype,
183                                               CodecInstToSdp(codecInst_B)));
184 
185   //--- Set ref-A codecs
186   EXPECT_GT(_acmRefA->RegisterSendCodec(codecInst_A), -1);
187   EXPECT_EQ(true, _acmRefA->RegisterReceiveCodec(codecInst_B.pltype,
188                                                  CodecInstToSdp(codecInst_B)));
189 
190   //--- Set B codecs
191   EXPECT_GT(_acmB->RegisterSendCodec(codecInst_B), -1);
192   EXPECT_EQ(true, _acmB->RegisterReceiveCodec(codecInst_A.pltype,
193                                               CodecInstToSdp(codecInst_A)));
194 
195   //--- Set ref-B codecs
196   EXPECT_EQ(0, _acmRefB->RegisterSendCodec(codecInst_B));
197   EXPECT_EQ(true, _acmRefB->RegisterReceiveCodec(codecInst_A.pltype,
198                                                  CodecInstToSdp(codecInst_A)));
199 
200   uint16_t frequencyHz;
201 
202   //--- Input A and B
203   std::string in_file_name = webrtc::test::ResourcePath(
204       "audio_coding/testfile32kHz", "pcm");
205   frequencyHz = 16000;
206   _inFileA.Open(in_file_name, frequencyHz, "rb");
207   _inFileB.Open(in_file_name, frequencyHz, "rb");
208 
209   //--- Output A
210   std::string output_file_a = webrtc::test::OutputPath() + "outAutotestA.pcm";
211   frequencyHz = 16000;
212   _outFileA.Open(output_file_a, frequencyHz, "wb");
213   std::string output_ref_file_a = webrtc::test::OutputPath()
214       + "ref_outAutotestA.pcm";
215   _outFileRefA.Open(output_ref_file_a, frequencyHz, "wb");
216 
217   //--- Output B
218   std::string output_file_b = webrtc::test::OutputPath() + "outAutotestB.pcm";
219   frequencyHz = 16000;
220   _outFileB.Open(output_file_b, frequencyHz, "wb");
221   std::string output_ref_file_b = webrtc::test::OutputPath()
222       + "ref_outAutotestB.pcm";
223   _outFileRefB.Open(output_ref_file_b, frequencyHz, "wb");
224 
225   //--- Set A-to-B channel
226   _channel_A2B = new Channel;
227   _acmA->RegisterTransportCallback(_channel_A2B);
228   _channel_A2B->RegisterReceiverACM(_acmB.get());
229   //--- Do the same for the reference
230   _channelRef_A2B = new Channel;
231   _acmRefA->RegisterTransportCallback(_channelRef_A2B);
232   _channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
233 
234   //--- Set B-to-A channel
235   _channel_B2A = new Channel;
236   _acmB->RegisterTransportCallback(_channel_B2A);
237   _channel_B2A->RegisterReceiverACM(_acmA.get());
238   //--- Do the same for reference
239   _channelRef_B2A = new Channel;
240   _acmRefB->RegisterTransportCallback(_channelRef_B2A);
241   _channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
242 }
243 
Perform()244 void TwoWayCommunication::Perform() {
245   if (_testMode == 0) {
246     SetUpAutotest();
247   } else {
248     SetUp();
249   }
250   unsigned int msecPassed = 0;
251   unsigned int secPassed = 0;
252 
253   int32_t outFreqHzA = _outFileA.SamplingFrequency();
254   int32_t outFreqHzB = _outFileB.SamplingFrequency();
255 
256   AudioFrame audioFrame;
257 
258   auto codecInst_B = _acmB->SendCodec();
259   ASSERT_TRUE(codecInst_B);
260 
261   // In the following loop we tests that the code can handle misuse of the APIs.
262   // In the middle of a session with data flowing between two sides, called A
263   // and B, APIs will be called, and the code should continue to run, and be
264   // able to recover.
265   while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) {
266     msecPassed += 10;
267     EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
268     EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
269     EXPECT_GE(_acmRefA->Add10MsData(audioFrame), 0);
270 
271     EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0);
272 
273     EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
274     EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0);
275     bool muted;
276     EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame, &muted));
277     ASSERT_FALSE(muted);
278     _outFileA.Write10MsData(audioFrame);
279     EXPECT_EQ(0, _acmRefA->PlayoutData10Ms(outFreqHzA, &audioFrame, &muted));
280     ASSERT_FALSE(muted);
281     _outFileRefA.Write10MsData(audioFrame);
282     EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
283     ASSERT_FALSE(muted);
284     _outFileB.Write10MsData(audioFrame);
285     EXPECT_EQ(0, _acmRefB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
286     ASSERT_FALSE(muted);
287     _outFileRefB.Write10MsData(audioFrame);
288 
289     // Update time counters each time a second of data has passed.
290     if (msecPassed >= 1000) {
291       msecPassed = 0;
292       secPassed++;
293     }
294     // Re-register send codec on side B.
295     if (((secPassed % 5) == 4) && (msecPassed >= 990)) {
296       EXPECT_EQ(0, _acmB->RegisterSendCodec(*codecInst_B));
297       EXPECT_TRUE(_acmB->SendCodec());
298     }
299     // Initialize receiver on side A.
300     if (((secPassed % 7) == 6) && (msecPassed == 0))
301       EXPECT_EQ(0, _acmA->InitializeReceiver());
302     // Re-register codec on side A.
303     if (((secPassed % 7) == 6) && (msecPassed >= 990)) {
304       EXPECT_EQ(true, _acmA->RegisterReceiveCodec(
305                           codecInst_B->pltype, CodecInstToSdp(*codecInst_B)));
306     }
307   }
308 }
309 
310 }  // namespace webrtc
311