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/TestRedFec.h"
12
13 #include <assert.h>
14
15 #include "webrtc/common.h"
16 #include "webrtc/common_types.h"
17 #include "webrtc/engine_configurations.h"
18 #include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
19 #include "webrtc/modules/audio_coding/test/utility.h"
20 #include "webrtc/system_wrappers/include/trace.h"
21 #include "webrtc/test/testsupport/fileutils.h"
22
23 #ifdef SUPPORT_RED_WB
24 #undef SUPPORT_RED_WB
25 #endif
26
27 #ifdef SUPPORT_RED_SWB
28 #undef SUPPORT_RED_SWB
29 #endif
30
31 #ifdef SUPPORT_RED_FB
32 #undef SUPPORT_RED_FB
33 #endif
34
35 namespace webrtc {
36
37 namespace {
38 const char kNameL16[] = "L16";
39 const char kNamePCMU[] = "PCMU";
40 const char kNameCN[] = "CN";
41 const char kNameRED[] = "RED";
42
43 // These three are only used by code #ifdeffed on WEBRTC_CODEC_G722.
44 #ifdef WEBRTC_CODEC_G722
45 const char kNameISAC[] = "ISAC";
46 const char kNameG722[] = "G722";
47 const char kNameOPUS[] = "opus";
48 #endif
49 }
50
TestRedFec()51 TestRedFec::TestRedFec()
52 : _acmA(AudioCodingModule::Create(0)),
53 _acmB(AudioCodingModule::Create(1)),
54 _channelA2B(NULL),
55 _testCntr(0) {
56 }
57
~TestRedFec()58 TestRedFec::~TestRedFec() {
59 if (_channelA2B != NULL) {
60 delete _channelA2B;
61 _channelA2B = NULL;
62 }
63 }
64
Perform()65 void TestRedFec::Perform() {
66 const std::string file_name = webrtc::test::ResourcePath(
67 "audio_coding/testfile32kHz", "pcm");
68 _inFileA.Open(file_name, 32000, "rb");
69
70 ASSERT_EQ(0, _acmA->InitializeReceiver());
71 ASSERT_EQ(0, _acmB->InitializeReceiver());
72
73 uint8_t numEncoders = _acmA->NumberOfCodecs();
74 CodecInst myCodecParam;
75 for (uint8_t n = 0; n < numEncoders; n++) {
76 EXPECT_EQ(0, _acmB->Codec(n, &myCodecParam));
77 // Default number of channels is 2 for opus, so we change to 1 in this test.
78 if (!strcmp(myCodecParam.plname, "opus")) {
79 myCodecParam.channels = 1;
80 }
81 EXPECT_EQ(0, _acmB->RegisterReceiveCodec(myCodecParam));
82 }
83
84 // Create and connect the channel
85 _channelA2B = new Channel;
86 _acmA->RegisterTransportCallback(_channelA2B);
87 _channelA2B->RegisterReceiverACM(_acmB.get());
88
89 EXPECT_EQ(0, RegisterSendCodec('A', kNameL16, 8000));
90 EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 8000));
91 EXPECT_EQ(0, RegisterSendCodec('A', kNameRED));
92 EXPECT_EQ(0, SetVAD(true, true, VADAggr));
93 EXPECT_EQ(0, _acmA->SetREDStatus(true));
94 EXPECT_TRUE(_acmA->REDStatus());
95
96 OpenOutFile(_testCntr);
97 Run();
98 _outFileB.Close();
99
100 RegisterSendCodec('A', kNamePCMU, 8000);
101 // Switch to another 8 kHz codec, RED should remain switched on.
102 EXPECT_TRUE(_acmA->REDStatus());
103 OpenOutFile(_testCntr);
104 Run();
105 _outFileB.Close();
106
107 #ifndef WEBRTC_CODEC_G722
108 EXPECT_TRUE(false);
109 printf("G722 needs to be activated to run this test\n");
110 return;
111 #else
112 EXPECT_EQ(0, RegisterSendCodec('A', kNameG722, 16000));
113 EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000));
114
115 #ifdef SUPPORT_RED_WB
116 // Switch codec, RED should remain.
117 EXPECT_TRUE(_acmA->REDStatus());
118 #else
119 // Switch to a 16 kHz codec, RED should have been switched off.
120 EXPECT_FALSE(_acmA->REDStatus());
121 #endif
122
123 OpenOutFile(_testCntr);
124 EXPECT_EQ(0, SetVAD(true, true, VADAggr));
125 EXPECT_EQ(0, _acmA->SetREDStatus(false));
126 EXPECT_FALSE(_acmA->REDStatus());
127 Run();
128 #ifdef SUPPORT_RED_WB
129 EXPECT_EQ(0, _acmA->SetREDStatus(true));
130 EXPECT_TRUE(_acmA->REDStatus());
131 #else
132 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
133 EXPECT_FALSE(_acmA->REDStatus());
134 #endif
135 Run();
136 _outFileB.Close();
137
138 RegisterSendCodec('A', kNameISAC, 16000);
139
140 #ifdef SUPPORT_RED_WB
141 // Switch codec, RED should remain.
142 EXPECT_TRUE(_acmA->REDStatus());
143 #else
144 EXPECT_FALSE(_acmA->REDStatus());
145 #endif
146
147 OpenOutFile(_testCntr);
148 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
149 EXPECT_EQ(0, _acmA->SetREDStatus(false));
150 EXPECT_FALSE(_acmA->REDStatus());
151 Run();
152 _outFileB.Close();
153
154 #ifdef SUPPORT_RED_WB
155 EXPECT_EQ(0, _acmA->SetREDStatus(true));
156 EXPECT_TRUE(_acmA->REDStatus());
157 #else
158 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
159 EXPECT_FALSE(_acmA->REDStatus());
160 #endif
161 OpenOutFile(_testCntr);
162 Run();
163 _outFileB.Close();
164
165 RegisterSendCodec('A', kNameISAC, 32000);
166
167 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
168 // Switch codec, RED should remain.
169 EXPECT_TRUE(_acmA->REDStatus());
170 #else
171 // Switch to a 32 kHz codec, RED should have been switched off.
172 EXPECT_FALSE(_acmA->REDStatus());
173 #endif
174
175 OpenOutFile(_testCntr);
176 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
177 EXPECT_EQ(0, _acmA->SetREDStatus(false));
178 EXPECT_FALSE(_acmA->REDStatus());
179 Run();
180 _outFileB.Close();
181
182 #ifdef SUPPORT_RED_SWB
183 EXPECT_EQ(0, _acmA->SetREDStatus(true));
184 EXPECT_TRUE(_acmA->REDStatus());
185 #else
186 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
187 EXPECT_FALSE(_acmA->REDStatus());
188 #endif
189 OpenOutFile(_testCntr);
190 Run();
191 _outFileB.Close();
192
193 RegisterSendCodec('A', kNameISAC, 32000);
194 EXPECT_EQ(0, SetVAD(false, false, VADNormal));
195
196 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
197 OpenOutFile(_testCntr);
198 EXPECT_EQ(0, _acmA->SetREDStatus(true));
199 EXPECT_TRUE(_acmA->REDStatus());
200 Run();
201
202 RegisterSendCodec('A', kNameISAC, 16000);
203 EXPECT_TRUE(_acmA->REDStatus());
204 Run();
205
206 RegisterSendCodec('A', kNameISAC, 32000);
207 EXPECT_TRUE(_acmA->REDStatus());
208 Run();
209
210 RegisterSendCodec('A', kNameISAC, 16000);
211 EXPECT_TRUE(_acmA->REDStatus());
212 Run();
213 _outFileB.Close();
214 #else
215 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
216 EXPECT_FALSE(_acmA->REDStatus());
217 #endif
218
219 _channelA2B->SetFECTestWithPacketLoss(true);
220 // Following tests are under packet losses.
221
222 EXPECT_EQ(0, RegisterSendCodec('A', kNameG722));
223 EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000));
224
225 #if defined(SUPPORT_RED_WB) && defined(SUPPORT_RED_SWB)
226 // Switch codec, RED should remain.
227 EXPECT_TRUE(_acmA->REDStatus());
228 #else
229 // Switch to a 16 kHz codec, RED should have been switched off.
230 EXPECT_FALSE(_acmA->REDStatus());
231 #endif
232
233 OpenOutFile(_testCntr);
234 EXPECT_EQ(0, SetVAD(true, true, VADAggr));
235 EXPECT_EQ(0, _acmA->SetREDStatus(false));
236 EXPECT_FALSE(_acmA->REDStatus());
237 Run();
238 _outFileB.Close();
239
240 #ifdef SUPPORT_RED_WB
241 EXPECT_EQ(0, _acmA->SetREDStatus(true));
242 EXPECT_TRUE(_acmA->REDStatus());
243 #else
244 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
245 EXPECT_FALSE(_acmA->REDStatus());
246 #endif
247 OpenOutFile(_testCntr);
248 Run();
249 _outFileB.Close();
250
251 RegisterSendCodec('A', kNameISAC, 16000);
252
253 #ifdef SUPPORT_RED_WB
254 // Switch codec, RED should remain.
255 EXPECT_TRUE(_acmA->REDStatus());
256 #else
257 // Switch to a 16 kHz codec, RED should have been switched off.
258 EXPECT_FALSE(_acmA->REDStatus());
259 #endif
260
261 OpenOutFile(_testCntr);
262 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
263 EXPECT_EQ(0, _acmA->SetREDStatus(false));
264 EXPECT_FALSE(_acmA->REDStatus());
265 Run();
266 _outFileB.Close();
267 #ifdef SUPPORT_RED_WB
268 EXPECT_EQ(0, _acmA->SetREDStatus(true));
269 EXPECT_TRUE(_acmA->REDStatus());
270 #else
271 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
272 EXPECT_FALSE(_acmA->REDStatus());
273 #endif
274 OpenOutFile(_testCntr);
275 Run();
276 _outFileB.Close();
277
278 RegisterSendCodec('A', kNameISAC, 32000);
279
280 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
281 // Switch codec, RED should remain.
282 EXPECT_TRUE(_acmA->REDStatus());
283 #else
284 // Switch to a 32 kHz codec, RED should have been switched off.
285 EXPECT_FALSE(_acmA->REDStatus());
286 #endif
287
288 OpenOutFile(_testCntr);
289 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
290 EXPECT_EQ(0, _acmA->SetREDStatus(false));
291 EXPECT_FALSE(_acmA->REDStatus());
292 #ifdef SUPPORT_RED_SWB
293 EXPECT_EQ(0, _acmA->SetREDStatus(true));
294 EXPECT_TRUE(_acmA->REDStatus());
295 #else
296 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
297 EXPECT_FALSE(_acmA->REDStatus());
298 #endif
299 OpenOutFile(_testCntr);
300 Run();
301 _outFileB.Close();
302
303 RegisterSendCodec('A', kNameISAC, 32000);
304 EXPECT_EQ(0, SetVAD(false, false, VADNormal));
305 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
306 OpenOutFile(_testCntr);
307 EXPECT_EQ(0, _acmA->SetREDStatus(true));
308 EXPECT_TRUE(_acmA->REDStatus());
309 Run();
310
311 RegisterSendCodec('A', kNameISAC, 16000);
312 EXPECT_TRUE(_acmA->REDStatus());
313 Run();
314
315 RegisterSendCodec('A', kNameISAC, 32000);
316 EXPECT_TRUE(_acmA->REDStatus());
317 Run();
318
319 RegisterSendCodec('A', kNameISAC, 16000);
320 EXPECT_TRUE(_acmA->REDStatus());
321 Run();
322 _outFileB.Close();
323 #else
324 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
325 EXPECT_FALSE(_acmA->REDStatus());
326 #endif
327
328 #ifndef WEBRTC_CODEC_OPUS
329 EXPECT_TRUE(false);
330 printf("Opus needs to be activated to run this test\n");
331 return;
332 #endif
333
334 RegisterSendCodec('A', kNameOPUS, 48000);
335
336 #if defined(SUPPORT_RED_FB) && defined(SUPPORT_RED_SWB) &&\
337 defined(SUPPORT_RED_WB)
338 // Switch to codec, RED should remain switched on.
339 EXPECT_TRUE(_acmA->REDStatus());
340 #else
341 EXPECT_FALSE(_acmA->REDStatus());
342 #endif
343
344 // _channelA2B imposes 25% packet loss rate.
345 EXPECT_EQ(0, _acmA->SetPacketLossRate(25));
346
347 #ifdef SUPPORT_RED_FB
348 EXPECT_EQ(0, _acmA->SetREDStatus(true));
349 EXPECT_TRUE(_acmA->REDStatus());
350 // Codec FEC and RED are mutually exclusive.
351 EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
352
353 EXPECT_EQ(0, _acmA->SetREDStatus(false));
354 EXPECT_EQ(0, _acmA->SetCodecFEC(true));
355
356 // Codec FEC and RED are mutually exclusive.
357 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
358 #else
359 EXPECT_EQ(-1, _acmA->SetREDStatus(true));
360 EXPECT_FALSE(_acmA->REDStatus());
361 EXPECT_EQ(0, _acmA->SetCodecFEC(true));
362 #endif
363
364 EXPECT_TRUE(_acmA->CodecFEC());
365 OpenOutFile(_testCntr);
366 Run();
367
368 // Switch to L16 with RED.
369 RegisterSendCodec('A', kNameL16, 8000);
370 EXPECT_EQ(0, SetVAD(false, false, VADNormal));
371
372 // L16 does not support FEC, so FEC should be turned off automatically.
373 EXPECT_FALSE(_acmA->CodecFEC());
374
375 EXPECT_EQ(0, _acmA->SetREDStatus(true));
376 EXPECT_TRUE(_acmA->REDStatus());
377 Run();
378
379 // Switch to Opus again.
380 RegisterSendCodec('A', kNameOPUS, 48000);
381 #ifdef SUPPORT_RED_FB
382 // Switch to codec, RED should remain switched on.
383 EXPECT_TRUE(_acmA->REDStatus());
384 #else
385 EXPECT_FALSE(_acmA->REDStatus());
386 #endif
387 EXPECT_EQ(0, _acmA->SetREDStatus(false));
388 EXPECT_EQ(0, _acmA->SetCodecFEC(false));
389 Run();
390
391 EXPECT_EQ(0, _acmA->SetCodecFEC(true));
392 _outFileB.Close();
393
394 // Codecs does not support internal FEC, cannot enable FEC.
395 RegisterSendCodec('A', kNameG722, 16000);
396 EXPECT_FALSE(_acmA->REDStatus());
397 EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
398 EXPECT_FALSE(_acmA->CodecFEC());
399
400 RegisterSendCodec('A', kNameISAC, 16000);
401 EXPECT_FALSE(_acmA->REDStatus());
402 EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
403 EXPECT_FALSE(_acmA->CodecFEC());
404
405 // Codecs does not support internal FEC, disable FEC does not trigger failure.
406 RegisterSendCodec('A', kNameG722, 16000);
407 EXPECT_FALSE(_acmA->REDStatus());
408 EXPECT_EQ(0, _acmA->SetCodecFEC(false));
409 EXPECT_FALSE(_acmA->CodecFEC());
410
411 RegisterSendCodec('A', kNameISAC, 16000);
412 EXPECT_FALSE(_acmA->REDStatus());
413 EXPECT_EQ(0, _acmA->SetCodecFEC(false));
414 EXPECT_FALSE(_acmA->CodecFEC());
415
416 #endif // defined(WEBRTC_CODEC_G722)
417 }
418
SetVAD(bool enableDTX,bool enableVAD,ACMVADMode vadMode)419 int32_t TestRedFec::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) {
420 return _acmA->SetVAD(enableDTX, enableVAD, vadMode);
421 }
422
RegisterSendCodec(char side,const char * codecName,int32_t samplingFreqHz)423 int16_t TestRedFec::RegisterSendCodec(char side, const char* codecName,
424 int32_t samplingFreqHz) {
425 std::cout << std::flush;
426 AudioCodingModule* myACM;
427 switch (side) {
428 case 'A': {
429 myACM = _acmA.get();
430 break;
431 }
432 case 'B': {
433 myACM = _acmB.get();
434 break;
435 }
436 default:
437 return -1;
438 }
439
440 if (myACM == NULL) {
441 assert(false);
442 return -1;
443 }
444 CodecInst myCodecParam;
445 EXPECT_GT(AudioCodingModule::Codec(codecName, &myCodecParam,
446 samplingFreqHz, 1), -1);
447 EXPECT_GT(myACM->RegisterSendCodec(myCodecParam), -1);
448
449 // Initialization was successful.
450 return 0;
451 }
452
Run()453 void TestRedFec::Run() {
454 AudioFrame audioFrame;
455 int32_t outFreqHzB = _outFileB.SamplingFrequency();
456 // Set test length to 500 ms (50 blocks of 10 ms each).
457 _inFileA.SetNum10MsBlocksToRead(50);
458 // Fast-forward 1 second (100 blocks) since the file starts with silence.
459 _inFileA.FastForward(100);
460
461 while (!_inFileA.EndOfFile()) {
462 EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
463 EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
464 EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
465 _outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
466 }
467 _inFileA.Rewind();
468 }
469
OpenOutFile(int16_t test_number)470 void TestRedFec::OpenOutFile(int16_t test_number) {
471 std::string file_name;
472 std::stringstream file_stream;
473 file_stream << webrtc::test::OutputPath();
474 file_stream << "TestRedFec_outFile_";
475 file_stream << test_number << ".pcm";
476 file_name = file_stream.str();
477 _outFileB.Open(file_name, 16000, "wb");
478 }
479
480 } // namespace webrtc
481