OLD | NEW |
| (Empty) |
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 // Refer to kUsage below for a description. | |
12 | |
13 #include <memory> | |
14 | |
15 #include "gflags/gflags.h" | |
16 #include "webrtc/base/checks.h" | |
17 #include "webrtc/base/format_macros.h" | |
18 #include "webrtc/system_wrappers/include/sleep.h" | |
19 #include "webrtc/system_wrappers/include/trace.h" | |
20 #include "webrtc/test/channel_transport/channel_transport.h" | |
21 #include "webrtc/test/testsupport/trace_to_stderr.h" | |
22 #include "webrtc/modules/audio_processing/include/audio_processing.h" | |
23 #include "webrtc/voice_engine/include/voe_audio_processing.h" | |
24 #include "webrtc/voice_engine/include/voe_base.h" | |
25 #include "webrtc/voice_engine/include/voe_codec.h" | |
26 #include "webrtc/voice_engine/include/voe_external_media.h" | |
27 #include "webrtc/voice_engine/include/voe_file.h" | |
28 #include "webrtc/voice_engine/include/voe_hardware.h" | |
29 #include "webrtc/voice_engine/include/voe_network.h" | |
30 #include "webrtc/voice_engine/include/voe_volume_control.h" | |
31 | |
32 DEFINE_bool(codecs, false, "print out available codecs"); | |
33 DEFINE_int32(pt, 120, "codec payload type (defaults to opus/48000/2)"); | |
34 DEFINE_bool(legacy_agc, | |
35 false, | |
36 "use the legacy AGC in 'serial' mode, or as the first voice " | |
37 "engine's AGC in parallel mode"); | |
38 DEFINE_bool(parallel, | |
39 false, | |
40 "run new and legacy AGCs in parallel, with left- and right-panning " | |
41 "respectively. Not compatible with -aec."); | |
42 DEFINE_bool(devices, false, "print out capture devices and indexes to be used " | |
43 "with the capture flags"); | |
44 DEFINE_int32(capture1, 0, "capture device index for the first voice engine"); | |
45 DEFINE_int32(capture2, 0, "capture device index for second voice engine"); | |
46 DEFINE_int32(render1, 0, "render device index for first voice engine"); | |
47 DEFINE_int32(render2, 0, "render device index for second voice engine"); | |
48 DEFINE_bool(aec, | |
49 false, | |
50 "runs two voice engines in parallel, with the first playing out a " | |
51 "file and sending its captured signal to the second voice engine. " | |
52 "Also enables echo cancellation."); | |
53 DEFINE_bool(ns, true, "enable noise suppression"); | |
54 DEFINE_bool(highpass, true, "enable high pass filter"); | |
55 DEFINE_string(filename, "", "filename for the -aec mode"); | |
56 | |
57 namespace webrtc { | |
58 namespace { | |
59 | |
60 const char kUsage[] = | |
61 "\nWithout additional flags, sets up a simple VoiceEngine loopback call\n" | |
62 "with the default audio devices and runs forever.\n" | |
63 | |
64 "It can also run the new and legacy AGCs in parallel, panned to\n" | |
65 "opposite stereo channels on the default render device. The capture\n" | |
66 "devices for each can be selected (recommended, because otherwise they\n" | |
67 "will fight for the level on the same device).\n\n" | |
68 | |
69 "Lastly, it can be used for local AEC testing. In this mode, the first\n" | |
70 "voice engine plays out a file over the selected render device (normally\n" | |
71 "loudspeakers) and records from the selected capture device. The second\n" | |
72 "voice engine receives the capture signal and plays it out over the\n" | |
73 "selected render device (normally headphones). This allows the user to\n" | |
74 "test an echo scenario with the first voice engine, while monitoring the\n" | |
75 "result with the second."; | |
76 | |
77 class AgcVoiceEngine { | |
78 public: | |
79 enum Pan { | |
80 NoPan, | |
81 PanLeft, | |
82 PanRight | |
83 }; | |
84 | |
85 AgcVoiceEngine(bool legacy_agc, | |
86 int tx_port, | |
87 int rx_port, | |
88 int capture_idx, | |
89 int render_idx) | |
90 : voe_(VoiceEngine::Create()), | |
91 base_(VoEBase::GetInterface(voe_)), | |
92 hardware_(VoEHardware::GetInterface(voe_)), | |
93 codec_(VoECodec::GetInterface(voe_)), | |
94 channel_(-1), | |
95 capture_idx_(capture_idx), | |
96 render_idx_(render_idx) { | |
97 SetUp(legacy_agc, tx_port, rx_port); | |
98 } | |
99 | |
100 ~AgcVoiceEngine() { | |
101 TearDown(); | |
102 } | |
103 | |
104 void SetUp(bool legacy_agc, int tx_port, int rx_port) { | |
105 VoEAudioProcessing* audio = VoEAudioProcessing::GetInterface(voe_); | |
106 VoENetwork* network = VoENetwork::GetInterface(voe_); | |
107 { | |
108 webrtc::Config config; | |
109 config.Set<ExperimentalAgc>(new ExperimentalAgc(!legacy_agc)); | |
110 AudioProcessing* audioproc = AudioProcessing::Create(config); | |
111 RTC_CHECK_EQ(0, base_->Init(nullptr, audioproc)); | |
112 // Set this stuff after Init, to override the default voice engine | |
113 // settings. | |
114 audioproc->gain_control()->Enable(true); | |
115 audioproc->high_pass_filter()->Enable(FLAGS_highpass); | |
116 audioproc->noise_suppression()->Enable(FLAGS_ns); | |
117 audioproc->echo_cancellation()->Enable(FLAGS_aec); | |
118 } | |
119 channel_ = base_->CreateChannel(); | |
120 RTC_CHECK_NE(-1, channel_); | |
121 | |
122 channel_transport_.reset( | |
123 new test::VoiceChannelTransport(network, channel_)); | |
124 RTC_CHECK_EQ(0, | |
125 channel_transport_->SetSendDestination("127.0.0.1", tx_port)); | |
126 RTC_CHECK_EQ(0, channel_transport_->SetLocalReceiver(rx_port)); | |
127 | |
128 RTC_CHECK_EQ(0, hardware_->SetRecordingDevice(capture_idx_)); | |
129 RTC_CHECK_EQ(0, hardware_->SetPlayoutDevice(render_idx_)); | |
130 | |
131 CodecInst codec_params = {}; | |
132 bool codec_found = false; | |
133 for (int i = 0; i < codec_->NumOfCodecs(); i++) { | |
134 RTC_CHECK_EQ(0, codec_->GetCodec(i, codec_params)); | |
135 if (FLAGS_pt == codec_params.pltype) { | |
136 codec_found = true; | |
137 break; | |
138 } | |
139 } | |
140 RTC_CHECK(codec_found); | |
141 RTC_CHECK_EQ(0, codec_->SetSendCodec(channel_, codec_params)); | |
142 | |
143 audio->Release(); | |
144 network->Release(); | |
145 } | |
146 | |
147 void TearDown() { | |
148 Stop(); | |
149 channel_transport_.reset(nullptr); | |
150 RTC_CHECK_EQ(0, base_->DeleteChannel(channel_)); | |
151 RTC_CHECK_EQ(0, base_->Terminate()); | |
152 hardware_->Release(); | |
153 base_->Release(); | |
154 codec_->Release(); | |
155 RTC_CHECK(VoiceEngine::Delete(voe_)); | |
156 } | |
157 | |
158 void PrintDevices() { | |
159 int num_devices = 0; | |
160 char device_name[128] = {0}; | |
161 char guid[128] = {0}; | |
162 RTC_CHECK_EQ(0, hardware_->GetNumOfRecordingDevices(num_devices)); | |
163 printf("Capture devices:\n"); | |
164 for (int i = 0; i < num_devices; i++) { | |
165 RTC_CHECK_EQ(0, hardware_->GetRecordingDeviceName(i, device_name, guid)); | |
166 printf("%d: %s\n", i, device_name); | |
167 } | |
168 RTC_CHECK_EQ(0, hardware_->GetNumOfPlayoutDevices(num_devices)); | |
169 printf("Render devices:\n"); | |
170 for (int i = 0; i < num_devices; i++) { | |
171 RTC_CHECK_EQ(0, hardware_->GetPlayoutDeviceName(i, device_name, guid)); | |
172 printf("%d: %s\n", i, device_name); | |
173 } | |
174 } | |
175 | |
176 void PrintCodecs() { | |
177 CodecInst params = {0}; | |
178 printf("Codecs:\n"); | |
179 for (int i = 0; i < codec_->NumOfCodecs(); i++) { | |
180 RTC_CHECK_EQ(0, codec_->GetCodec(i, params)); | |
181 printf("%d %s/%d/%" PRIuS "\n", params.pltype, params.plname, | |
182 params.plfreq, params.channels); | |
183 } | |
184 } | |
185 | |
186 void StartSending() { RTC_CHECK_EQ(0, base_->StartSend(channel_)); } | |
187 | |
188 void StartPlaying(Pan pan, const std::string& filename) { | |
189 VoEVolumeControl* volume = VoEVolumeControl::GetInterface(voe_); | |
190 VoEFile* file = VoEFile::GetInterface(voe_); | |
191 if (pan == PanLeft) { | |
192 volume->SetOutputVolumePan(channel_, 1, 0); | |
193 } else if (pan == PanRight) { | |
194 volume->SetOutputVolumePan(channel_, 0, 1); | |
195 } | |
196 if (filename != "") { | |
197 printf("playing file\n"); | |
198 RTC_CHECK_EQ( | |
199 0, file->StartPlayingFileLocally(channel_, filename.c_str(), true, | |
200 kFileFormatPcm16kHzFile, 1.0, 0, 0)); | |
201 } | |
202 RTC_CHECK_EQ(0, base_->StartReceive(channel_)); | |
203 RTC_CHECK_EQ(0, base_->StartPlayout(channel_)); | |
204 volume->Release(); | |
205 file->Release(); | |
206 } | |
207 | |
208 void Stop() { | |
209 RTC_CHECK_EQ(0, base_->StopSend(channel_)); | |
210 RTC_CHECK_EQ(0, base_->StopPlayout(channel_)); | |
211 } | |
212 | |
213 private: | |
214 VoiceEngine* voe_; | |
215 VoEBase* base_; | |
216 VoEHardware* hardware_; | |
217 VoECodec* codec_; | |
218 int channel_; | |
219 int capture_idx_; | |
220 int render_idx_; | |
221 std::unique_ptr<test::VoiceChannelTransport> channel_transport_; | |
222 }; | |
223 | |
224 void RunHarness() { | |
225 std::unique_ptr<AgcVoiceEngine> voe1(new AgcVoiceEngine( | |
226 FLAGS_legacy_agc, 2000, 2000, FLAGS_capture1, FLAGS_render1)); | |
227 std::unique_ptr<AgcVoiceEngine> voe2; | |
228 if (FLAGS_parallel) { | |
229 voe2.reset(new AgcVoiceEngine(!FLAGS_legacy_agc, 3000, 3000, FLAGS_capture2, | |
230 FLAGS_render2)); | |
231 voe1->StartPlaying(AgcVoiceEngine::PanLeft, ""); | |
232 voe1->StartSending(); | |
233 voe2->StartPlaying(AgcVoiceEngine::PanRight, ""); | |
234 voe2->StartSending(); | |
235 } else if (FLAGS_aec) { | |
236 voe1.reset(new AgcVoiceEngine(FLAGS_legacy_agc, 2000, 4242, FLAGS_capture1, | |
237 FLAGS_render1)); | |
238 voe2.reset(new AgcVoiceEngine(!FLAGS_legacy_agc, 4242, 2000, FLAGS_capture2, | |
239 FLAGS_render2)); | |
240 voe1->StartPlaying(AgcVoiceEngine::NoPan, FLAGS_filename); | |
241 voe1->StartSending(); | |
242 voe2->StartPlaying(AgcVoiceEngine::NoPan, ""); | |
243 } else { | |
244 voe1->StartPlaying(AgcVoiceEngine::NoPan, ""); | |
245 voe1->StartSending(); | |
246 } | |
247 | |
248 // Run forever... | |
249 SleepMs(0x7fffffff); | |
250 } | |
251 | |
252 void PrintDevices() { | |
253 AgcVoiceEngine device_voe(false, 4242, 4242, 0, 0); | |
254 device_voe.PrintDevices(); | |
255 } | |
256 | |
257 void PrintCodecs() { | |
258 AgcVoiceEngine codec_voe(false, 4242, 4242, 0, 0); | |
259 codec_voe.PrintCodecs(); | |
260 } | |
261 | |
262 } // namespace | |
263 } // namespace webrtc | |
264 | |
265 int main(int argc, char** argv) { | |
266 google::SetUsageMessage(webrtc::kUsage); | |
267 google::ParseCommandLineFlags(&argc, &argv, true); | |
268 webrtc::test::TraceToStderr trace_to_stderr; | |
269 | |
270 if (FLAGS_parallel && FLAGS_aec) { | |
271 printf("-parallel and -aec are not compatible\n"); | |
272 return 1; | |
273 } | |
274 if (FLAGS_devices) { | |
275 webrtc::PrintDevices(); | |
276 } | |
277 if (FLAGS_codecs) { | |
278 webrtc::PrintCodecs(); | |
279 } | |
280 if (!FLAGS_devices && !FLAGS_codecs) { | |
281 webrtc::RunHarness(); | |
282 } | |
283 return 0; | |
284 } | |
OLD | NEW |