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 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
20 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
21 #include "modules/audio_coding/test/PCMFile.h"
22 #include "test/gtest.h"
23 #include "test/testsupport/file_utils.h"
24 
25 namespace webrtc {
26 
27 #define MAX_FILE_NAME_LENGTH_BYTE 500
28 
TwoWayCommunication()29 TwoWayCommunication::TwoWayCommunication()
30     : _acmA(AudioCodingModule::Create(
31           AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
32       _acmRefA(AudioCodingModule::Create(
33           AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))) {
34   AudioCodingModule::Config config;
35   // The clicks will be more obvious if time-stretching is not allowed.
36   // TODO(henrik.lundin) Really?
37   config.neteq_config.for_test_no_time_stretching = true;
38   config.decoder_factory = CreateBuiltinAudioDecoderFactory();
39   _acmB.reset(AudioCodingModule::Create(config));
40   _acmRefB.reset(AudioCodingModule::Create(config));
41 }
42 
~TwoWayCommunication()43 TwoWayCommunication::~TwoWayCommunication() {
44   delete _channel_A2B;
45   delete _channel_B2A;
46   delete _channelRef_A2B;
47   delete _channelRef_B2A;
48   _inFileA.Close();
49   _inFileB.Close();
50   _outFileA.Close();
51   _outFileB.Close();
52   _outFileRefA.Close();
53   _outFileRefB.Close();
54 }
55 
SetUpAutotest(AudioEncoderFactory * const encoder_factory,const SdpAudioFormat & format1,const int payload_type1,const SdpAudioFormat & format2,const int payload_type2)56 void TwoWayCommunication::SetUpAutotest(
57     AudioEncoderFactory* const encoder_factory,
58     const SdpAudioFormat& format1,
59     const int payload_type1,
60     const SdpAudioFormat& format2,
61     const int payload_type2) {
62   //--- Set A codecs
63   _acmA->SetEncoder(
64       encoder_factory->MakeAudioEncoder(payload_type1, format1, absl::nullopt));
65   _acmA->SetReceiveCodecs({{payload_type2, format2}});
66 
67   //--- Set ref-A codecs
68   _acmRefA->SetEncoder(
69       encoder_factory->MakeAudioEncoder(payload_type1, format1, absl::nullopt));
70   _acmRefA->SetReceiveCodecs({{payload_type2, format2}});
71 
72   //--- Set B codecs
73   _acmB->SetEncoder(
74       encoder_factory->MakeAudioEncoder(payload_type2, format2, absl::nullopt));
75   _acmB->SetReceiveCodecs({{payload_type1, format1}});
76 
77   //--- Set ref-B codecs
78   _acmRefB->SetEncoder(
79       encoder_factory->MakeAudioEncoder(payload_type2, format2, absl::nullopt));
80   _acmRefB->SetReceiveCodecs({{payload_type1, format1}});
81 
82   uint16_t frequencyHz;
83 
84   //--- Input A and B
85   std::string in_file_name =
86       webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
87   frequencyHz = 16000;
88   _inFileA.Open(in_file_name, frequencyHz, "rb");
89   _inFileB.Open(in_file_name, frequencyHz, "rb");
90 
91   //--- Output A
92   std::string output_file_a = webrtc::test::OutputPath() + "outAutotestA.pcm";
93   frequencyHz = 16000;
94   _outFileA.Open(output_file_a, frequencyHz, "wb");
95   std::string output_ref_file_a =
96       webrtc::test::OutputPath() + "ref_outAutotestA.pcm";
97   _outFileRefA.Open(output_ref_file_a, frequencyHz, "wb");
98 
99   //--- Output B
100   std::string output_file_b = webrtc::test::OutputPath() + "outAutotestB.pcm";
101   frequencyHz = 16000;
102   _outFileB.Open(output_file_b, frequencyHz, "wb");
103   std::string output_ref_file_b =
104       webrtc::test::OutputPath() + "ref_outAutotestB.pcm";
105   _outFileRefB.Open(output_ref_file_b, frequencyHz, "wb");
106 
107   //--- Set A-to-B channel
108   _channel_A2B = new Channel;
109   _acmA->RegisterTransportCallback(_channel_A2B);
110   _channel_A2B->RegisterReceiverACM(_acmB.get());
111   //--- Do the same for the reference
112   _channelRef_A2B = new Channel;
113   _acmRefA->RegisterTransportCallback(_channelRef_A2B);
114   _channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
115 
116   //--- Set B-to-A channel
117   _channel_B2A = new Channel;
118   _acmB->RegisterTransportCallback(_channel_B2A);
119   _channel_B2A->RegisterReceiverACM(_acmA.get());
120   //--- Do the same for reference
121   _channelRef_B2A = new Channel;
122   _acmRefB->RegisterTransportCallback(_channelRef_B2A);
123   _channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
124 }
125 
Perform()126 void TwoWayCommunication::Perform() {
127   const SdpAudioFormat format1("ISAC", 16000, 1);
128   const SdpAudioFormat format2("L16", 8000, 1);
129   constexpr int payload_type1 = 17, payload_type2 = 18;
130 
131   auto encoder_factory = CreateBuiltinAudioEncoderFactory();
132 
133   SetUpAutotest(encoder_factory.get(), format1, payload_type1, format2,
134                 payload_type2);
135 
136   unsigned int msecPassed = 0;
137   unsigned int secPassed = 0;
138 
139   int32_t outFreqHzA = _outFileA.SamplingFrequency();
140   int32_t outFreqHzB = _outFileB.SamplingFrequency();
141 
142   AudioFrame audioFrame;
143 
144   // In the following loop we tests that the code can handle misuse of the APIs.
145   // In the middle of a session with data flowing between two sides, called A
146   // and B, APIs will be called, and the code should continue to run, and be
147   // able to recover.
148   while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) {
149     msecPassed += 10;
150     EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
151     EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
152     EXPECT_GE(_acmRefA->Add10MsData(audioFrame), 0);
153 
154     EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0);
155 
156     EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
157     EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0);
158     bool muted;
159     EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame, &muted));
160     ASSERT_FALSE(muted);
161     _outFileA.Write10MsData(audioFrame);
162     EXPECT_EQ(0, _acmRefA->PlayoutData10Ms(outFreqHzA, &audioFrame, &muted));
163     ASSERT_FALSE(muted);
164     _outFileRefA.Write10MsData(audioFrame);
165     EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
166     ASSERT_FALSE(muted);
167     _outFileB.Write10MsData(audioFrame);
168     EXPECT_EQ(0, _acmRefB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
169     ASSERT_FALSE(muted);
170     _outFileRefB.Write10MsData(audioFrame);
171 
172     // Update time counters each time a second of data has passed.
173     if (msecPassed >= 1000) {
174       msecPassed = 0;
175       secPassed++;
176     }
177     // Re-register send codec on side B.
178     if (((secPassed % 5) == 4) && (msecPassed >= 990)) {
179       _acmB->SetEncoder(encoder_factory->MakeAudioEncoder(
180           payload_type2, format2, absl::nullopt));
181     }
182     // Initialize receiver on side A.
183     if (((secPassed % 7) == 6) && (msecPassed == 0))
184       EXPECT_EQ(0, _acmA->InitializeReceiver());
185     // Re-register codec on side A.
186     if (((secPassed % 7) == 6) && (msecPassed >= 990)) {
187       _acmA->SetReceiveCodecs({{payload_type2, format2}});
188     }
189   }
190 }
191 
192 }  // namespace webrtc
193