OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2016 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_processing/test/aec_dump_based_simulator.h" | |
12 | |
13 #include "webrtc/base/checks.h" | |
14 #include "webrtc/modules/audio_processing/test/protobuf_utils.h" | |
15 #include "webrtc/test/testsupport/trace_to_stderr.h" | |
16 | |
17 namespace webrtc { | |
18 namespace test { | |
19 namespace { | |
20 | |
21 // Verify output bitexactness for the fixed interface. | |
22 bool VerifyFixedBitExactness(const webrtc::audioproc::Stream& msg, | |
23 const AudioFrame& frame) { | |
24 if ((sizeof(int16_t) * frame.samples_per_channel_ * frame.num_channels_) != | |
25 msg.output_data().size()) { | |
26 return false; | |
27 } else { | |
28 for (size_t k = 0; k < frame.num_channels_ * frame.samples_per_channel_; | |
29 ++k) { | |
30 if (msg.output_data().data()[k] != frame.data_[k]) { | |
31 return false; | |
32 } | |
33 } | |
34 } | |
35 return true; | |
36 } | |
37 | |
38 // Verify output bitexactness for the float interface. | |
39 bool VerifyFloatBitExactness(const webrtc::audioproc::Stream& msg, | |
40 const StreamConfig& out_config, | |
41 const ChannelBuffer<float>& out_buf) { | |
42 if (static_cast<size_t>(msg.output_channel_size()) != | |
43 out_config.num_channels() || | |
44 msg.output_channel(0).size() != out_config.num_frames()) { | |
45 return false; | |
46 } else { | |
47 for (int ch = 0; ch < msg.output_channel_size(); ++ch) { | |
48 for (size_t sample = 0; sample < out_config.num_frames(); ++sample) { | |
49 if (msg.output_channel(ch).data()[sample] != | |
50 out_buf.channels()[ch][sample]) { | |
51 return false; | |
52 } | |
53 } | |
54 } | |
55 } | |
56 return true; | |
57 } | |
58 | |
59 } // namespace | |
60 | |
61 void AecDumpBasedSimulator::PrepareProcessStreamCall( | |
62 const webrtc::audioproc::Stream& msg) { | |
63 if (msg.has_input_data()) { | |
64 // Fixed interface processing. | |
65 // Verify interface invariance. | |
66 RTC_CHECK(interface_used_ == InterfaceType::kFixedInterface || | |
67 interface_used_ == InterfaceType::kNotSpecified); | |
68 interface_used_ = InterfaceType::kFixedInterface; | |
69 | |
70 // ProcessStream could have changed this for the output frame. | |
71 fwd_frame_.num_channels_ = ap_->num_input_channels(); | |
72 | |
73 // Populate input buffer. | |
74 RTC_CHECK_EQ(sizeof(fwd_frame_.data_[0]) * fwd_frame_.samples_per_channel_ * | |
75 fwd_frame_.num_channels_, | |
76 msg.input_data().size()); | |
77 memcpy(fwd_frame_.data_, msg.input_data().data(), msg.input_data().size()); | |
78 } else { | |
79 // Float interface processing. | |
80 // Verify interface invariance. | |
81 RTC_CHECK(interface_used_ == InterfaceType::kFloatInterface || | |
82 interface_used_ == InterfaceType::kNotSpecified); | |
83 interface_used_ = InterfaceType::kFloatInterface; | |
84 | |
85 RTC_CHECK_EQ(in_buf_->num_channels(), | |
86 static_cast<size_t>(msg.input_channel_size())); | |
87 | |
88 // Populate input buffer. | |
89 for (int i = 0; i < msg.input_channel_size(); ++i) { | |
90 RTC_CHECK_EQ(in_buf_->num_frames() * sizeof(*in_buf_->channels()[i]), | |
91 msg.input_channel(i).size()); | |
92 std::memcpy(in_buf_->channels()[i], msg.input_channel(i).data(), | |
93 msg.input_channel(i).size()); | |
94 } | |
95 } | |
96 | |
97 if (!settings_.stream_delay) { | |
98 if (msg.has_delay()) { | |
99 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
100 ap_->set_stream_delay_ms(msg.delay())); | |
101 } | |
102 } else { | |
103 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
104 ap_->set_stream_delay_ms(*settings_.stream_delay)); | |
105 } | |
106 | |
107 if (!settings_.stream_drift_samples) { | |
108 if (msg.has_drift()) { | |
109 ap_->echo_cancellation()->set_stream_drift_samples(msg.drift()); | |
110 } | |
111 } else { | |
112 ap_->echo_cancellation()->set_stream_drift_samples( | |
113 *settings_.stream_drift_samples); | |
114 } | |
115 | |
116 if (!settings_.use_ts) { | |
117 if (msg.has_keypress()) { | |
118 ap_->set_stream_key_pressed(msg.keypress()); | |
119 } | |
120 } else { | |
121 ap_->set_stream_key_pressed(*settings_.use_ts); | |
122 } | |
123 | |
124 // TODO(peah): Add support for controlling the analog level via the | |
125 // command-line. | |
126 if (msg.has_level()) { | |
127 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
128 ap_->gain_control()->set_stream_analog_level(msg.level())); | |
129 } | |
130 } | |
131 | |
132 void AecDumpBasedSimulator::VerifyProcessStreamBitExactness( | |
133 const webrtc::audioproc::Stream& msg) { | |
134 if (bitexact_output_) { | |
135 if (interface_used_ == InterfaceType::kFixedInterface) { | |
136 bitexact_output_ = VerifyFixedBitExactness(msg, fwd_frame_); | |
137 } else { | |
138 bitexact_output_ = VerifyFloatBitExactness(msg, out_config_, *out_buf_); | |
139 } | |
140 } | |
141 } | |
142 | |
143 void AecDumpBasedSimulator::PrepareReverseProcessStreamCall( | |
144 const webrtc::audioproc::ReverseStream& msg) { | |
145 if (msg.has_data()) { | |
146 // Fixed interface processing. | |
147 // Verify interface invariance. | |
148 RTC_CHECK(interface_used_ == InterfaceType::kFixedInterface || | |
149 interface_used_ == InterfaceType::kNotSpecified); | |
150 interface_used_ = InterfaceType::kFixedInterface; | |
151 | |
152 // Populate input buffer. | |
153 RTC_CHECK_EQ(sizeof(int16_t) * rev_frame_.samples_per_channel_ * | |
154 rev_frame_.num_channels_, | |
155 msg.data().size()); | |
156 memcpy(rev_frame_.data_, msg.data().data(), msg.data().size()); | |
157 } else { | |
158 // Float interface processing. | |
159 // Verify interface invariance. | |
160 RTC_CHECK(interface_used_ == InterfaceType::kFloatInterface || | |
161 interface_used_ == InterfaceType::kNotSpecified); | |
162 interface_used_ = InterfaceType::kFloatInterface; | |
163 | |
164 RTC_CHECK_EQ(reverse_in_buf_->num_channels(), | |
165 static_cast<size_t>(msg.channel_size())); | |
166 | |
167 // Populate input buffer. | |
168 for (int i = 0; i < msg.channel_size(); ++i) { | |
169 RTC_CHECK_EQ(reverse_in_buf_->num_frames() * | |
170 sizeof(*reverse_in_buf_->channels()[i]), | |
171 msg.channel(i).size()); | |
172 std::memcpy(reverse_in_buf_->channels()[i], msg.channel(i).data(), | |
173 msg.channel(i).size()); | |
174 } | |
175 } | |
176 } | |
177 | |
178 void AecDumpBasedSimulator::Process() { | |
179 std::unique_ptr<test::TraceToStderr> trace_to_stderr; | |
180 if (settings_.use_verbose_logging) { | |
181 trace_to_stderr.reset(new test::TraceToStderr(true)); | |
182 } | |
183 | |
184 CreateAudioProcessor(); | |
185 dump_input_file_ = OpenFile(settings_.aec_dump_input_filename->c_str(), "rb"); | |
186 | |
187 webrtc::audioproc::Event event_msg; | |
188 int num_forward_chunks_processed = 0; | |
189 const int kOneBykChunksPerSecond = | |
aluebs-webrtc
2016/05/09 16:27:32
float
peah-webrtc
2016/05/11 12:19:27
Good find!
Done.
| |
190 1.f / AudioProcessingSimulator::kChunksPerSecond; | |
191 while (ReadMessageFromFile(dump_input_file_, &event_msg)) { | |
192 switch (event_msg.type()) { | |
193 case webrtc::audioproc::Event::INIT: | |
194 RTC_CHECK(event_msg.has_init()); | |
195 HandleMessage(event_msg.init()); | |
196 break; | |
197 case webrtc::audioproc::Event::STREAM: | |
198 RTC_CHECK(event_msg.has_stream()); | |
199 HandleMessage(event_msg.stream()); | |
200 ++num_forward_chunks_processed; | |
201 break; | |
202 case webrtc::audioproc::Event::REVERSE_STREAM: | |
203 RTC_CHECK(event_msg.has_reverse_stream()); | |
204 HandleMessage(event_msg.reverse_stream()); | |
205 break; | |
206 case webrtc::audioproc::Event::CONFIG: | |
207 RTC_CHECK(event_msg.has_config()); | |
208 HandleMessage(event_msg.config()); | |
209 break; | |
210 default: | |
211 RTC_CHECK(false); | |
212 } | |
213 if (trace_to_stderr) { | |
214 trace_to_stderr->SetTimeSeconds(num_forward_chunks_processed * | |
215 kOneBykChunksPerSecond); | |
216 } | |
217 } | |
218 | |
219 fclose(dump_input_file_); | |
220 | |
221 DestroyAudioProcessor(); | |
222 } | |
223 | |
224 void AecDumpBasedSimulator::HandleMessage( | |
225 const webrtc::audioproc::Config& msg) { | |
226 if (settings_.use_verbose_logging) { | |
227 printf("Config at frame:\n "); | |
228 printf(" Forward: %zu\n", get_num_process_stream_calls()); | |
229 printf(" Reverse: %zu\n", get_num_reverse_process_stream_calls()); | |
230 } | |
231 | |
232 if (!settings_.discard_all_settings_in_aecdump) { | |
233 if (settings_.use_verbose_logging) { | |
234 printf("Setting used in config:\n"); | |
235 } | |
236 Config config; | |
237 | |
238 if (msg.has_aec_enabled() || settings_.use_aec) { | |
239 bool enable = settings_.use_aec ? *settings_.use_aec : msg.aec_enabled(); | |
240 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
241 ap_->echo_cancellation()->Enable(enable)); | |
242 if (settings_.use_verbose_logging) { | |
243 printf(" aec_enabled: %s\n", enable ? "true" : "false"); | |
244 } | |
245 } | |
246 | |
247 if (msg.has_aec_delay_agnostic_enabled() || settings_.use_delay_agnostic) { | |
248 bool enable = settings_.use_delay_agnostic | |
249 ? *settings_.use_delay_agnostic | |
250 : msg.aec_delay_agnostic_enabled(); | |
251 config.Set<DelayAgnostic>(new DelayAgnostic(enable)); | |
252 if (settings_.use_verbose_logging) { | |
253 printf(" aec_delay_agnostic_enabled: %s\n", enable ? "true" : "false"); | |
254 } | |
255 } | |
256 | |
257 if (msg.has_aec_drift_compensation_enabled() || | |
258 settings_.use_drift_compensation) { | |
259 bool enable = settings_.use_drift_compensation | |
260 ? *settings_.use_drift_compensation | |
261 : msg.aec_drift_compensation_enabled(); | |
262 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
263 ap_->echo_cancellation()->enable_drift_compensation(enable)); | |
264 if (settings_.use_verbose_logging) { | |
265 printf(" aec_drift_compensation_enabled: %s\n", | |
266 enable ? "true" : "false"); | |
267 } | |
268 } | |
269 | |
270 if (msg.has_aec_extended_filter_enabled() || | |
271 settings_.use_extended_filter) { | |
272 bool enable = settings_.use_extended_filter | |
273 ? *settings_.use_extended_filter | |
274 : msg.aec_extended_filter_enabled(); | |
275 config.Set<ExtendedFilter>(new ExtendedFilter(enable)); | |
276 if (settings_.use_verbose_logging) { | |
277 printf(" aec_extended_filter_enabled: %s\n", enable ? "true" : "false"); | |
278 } | |
279 } | |
280 | |
281 if (msg.has_aec_suppression_level() || settings_.aec_suppression_level) { | |
282 int level = settings_.aec_suppression_level | |
283 ? *settings_.aec_suppression_level | |
284 : msg.aec_suppression_level(); | |
285 RTC_CHECK_EQ( | |
286 AudioProcessing::kNoError, | |
287 ap_->echo_cancellation()->set_suppression_level( | |
288 static_cast<webrtc::EchoCancellation::SuppressionLevel>(level))); | |
289 if (settings_.use_verbose_logging) { | |
290 printf(" aec_suppression_level: %d\n", level); | |
291 } | |
292 } | |
293 | |
294 if (msg.has_aecm_enabled() || settings_.use_aecm) { | |
295 bool enable = | |
296 settings_.use_aecm ? *settings_.use_aecm : msg.aecm_enabled(); | |
297 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
298 ap_->echo_control_mobile()->Enable(enable)); | |
299 if (settings_.use_verbose_logging) { | |
300 printf(" aecm_enabled: %s\n", enable ? "true" : "false"); | |
301 } | |
302 } | |
303 | |
304 if (msg.has_aecm_comfort_noise_enabled() || | |
305 settings_.use_aecm_comfort_noise) { | |
306 bool enable = settings_.use_aecm_comfort_noise | |
307 ? *settings_.use_aecm_comfort_noise | |
308 : msg.aecm_comfort_noise_enabled(); | |
309 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
310 ap_->echo_control_mobile()->enable_comfort_noise(enable)); | |
311 if (settings_.use_verbose_logging) { | |
312 printf(" aecm_comfort_noise_enabled: %s\n", enable ? "true" : "false"); | |
313 } | |
314 } | |
315 | |
316 if (msg.has_aecm_routing_mode() || settings_.aecm_routing_mode) { | |
317 int routing_mode = settings_.aecm_routing_mode | |
318 ? *settings_.aecm_routing_mode | |
319 : msg.aecm_routing_mode(); | |
320 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
321 ap_->echo_control_mobile()->set_routing_mode( | |
322 static_cast<webrtc::EchoControlMobile::RoutingMode>( | |
323 routing_mode))); | |
324 if (settings_.use_verbose_logging) { | |
325 printf(" aecm_routing_mode: %d\n", routing_mode); | |
326 } | |
327 } | |
328 | |
329 if (msg.has_agc_enabled() || settings_.use_agc) { | |
330 bool enable = settings_.use_agc ? *settings_.use_agc : msg.agc_enabled(); | |
331 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
332 ap_->gain_control()->Enable(enable)); | |
333 if (settings_.use_verbose_logging) { | |
334 printf(" agc_enabled: %s\n", enable ? "true" : "false"); | |
335 } | |
336 } | |
337 | |
338 if (msg.has_agc_mode() || settings_.agc_mode) { | |
339 int mode = settings_.agc_mode ? *settings_.agc_mode : msg.agc_mode(); | |
340 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
341 ap_->gain_control()->set_mode( | |
342 static_cast<webrtc::GainControl::Mode>(mode))); | |
343 if (settings_.use_verbose_logging) { | |
344 printf(" agc_mode: %d\n", mode); | |
345 } | |
346 } | |
347 | |
348 if (msg.has_agc_limiter_enabled() || settings_.use_agc_limiter) { | |
349 bool enable = settings_.use_agc_limiter ? *settings_.use_agc_limiter | |
350 : msg.agc_limiter_enabled(); | |
351 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
352 ap_->gain_control()->enable_limiter(enable)); | |
353 if (settings_.use_verbose_logging) { | |
354 printf(" agc_limiter_enabled: %s\n", enable ? "true" : "false"); | |
355 } | |
356 } | |
357 | |
358 // TODO(peah): Add support for controlling the Experimental AGC from the | |
359 // command line. | |
360 if (msg.has_noise_robust_agc_enabled()) { | |
361 config.Set<ExperimentalAgc>( | |
362 new ExperimentalAgc(msg.noise_robust_agc_enabled())); | |
363 if (settings_.use_verbose_logging) { | |
364 printf(" noise_robust_agc_enabled: %s\n", | |
365 msg.noise_robust_agc_enabled() ? "true" : "false"); | |
366 } | |
367 } | |
368 | |
369 if (msg.has_transient_suppression_enabled() || settings_.use_ts) { | |
370 bool enable = settings_.use_ts ? *settings_.use_ts | |
371 : msg.transient_suppression_enabled(); | |
372 config.Set<ExperimentalNs>(new ExperimentalNs(enable)); | |
373 if (settings_.use_verbose_logging) { | |
374 printf(" transient_suppression_enabled: %s\n", | |
375 enable ? "true" : "false"); | |
376 } | |
377 } | |
378 | |
379 if (msg.has_hpf_enabled() || settings_.use_hpf) { | |
380 bool enable = settings_.use_hpf ? *settings_.use_hpf : msg.hpf_enabled(); | |
381 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
382 ap_->high_pass_filter()->Enable(enable)); | |
383 if (settings_.use_verbose_logging) { | |
384 printf(" hpf_enabled: %s\n", enable ? "true" : "false"); | |
385 } | |
386 } | |
387 | |
388 if (msg.has_ns_enabled() || settings_.use_ns) { | |
389 bool enable = settings_.use_ns ? *settings_.use_ns : msg.ns_enabled(); | |
390 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
391 ap_->noise_suppression()->Enable(enable)); | |
392 if (settings_.use_verbose_logging) { | |
393 printf(" ns_enabled: %s\n", enable ? "true" : "false"); | |
394 } | |
395 } | |
396 | |
397 if (msg.has_ns_level() || settings_.ns_level) { | |
398 int level = settings_.ns_level ? *settings_.ns_level : msg.ns_level(); | |
399 RTC_CHECK_EQ(AudioProcessing::kNoError, | |
400 ap_->noise_suppression()->set_level( | |
401 static_cast<NoiseSuppression::Level>(level))); | |
402 if (settings_.use_verbose_logging) { | |
403 printf(" ns_level: %d\n", level); | |
404 } | |
405 } | |
406 | |
407 if (settings_.use_verbose_logging && msg.has_experiments_description() && | |
408 msg.experiments_description().size() > 0) { | |
409 printf(" experiments not included by default in the simulation: %s\n", | |
410 msg.experiments_description().c_str()); | |
411 } | |
412 | |
413 if (settings_.use_refined_adaptive_filter) { | |
414 config.Set<RefinedAdaptiveFilter>( | |
415 new RefinedAdaptiveFilter(*settings_.use_refined_adaptive_filter)); | |
416 } | |
417 | |
418 if (settings_.use_aec3) { | |
419 config.Set<EchoCanceller3>(new EchoCanceller3(*settings_.use_aec3)); | |
420 } | |
421 | |
422 ap_->SetExtraOptions(config); | |
423 } | |
424 } | |
425 | |
426 void AecDumpBasedSimulator::HandleMessage(const webrtc::audioproc::Init& msg) { | |
427 RTC_CHECK(msg.has_sample_rate()); | |
428 RTC_CHECK(msg.has_num_input_channels()); | |
429 RTC_CHECK(msg.has_num_reverse_channels()); | |
430 RTC_CHECK(msg.has_reverse_sample_rate()); | |
431 | |
432 if (settings_.use_verbose_logging) { | |
433 printf("Init at frame:\n"); | |
434 printf(" Forward: %zu\n", get_num_process_stream_calls()); | |
435 printf(" Reverse: %zu\n", get_num_reverse_process_stream_calls()); | |
436 } | |
437 | |
438 int num_output_channels; | |
439 if (settings_.output_num_channels) { | |
440 num_output_channels = *settings_.output_num_channels; | |
441 } else { | |
442 num_output_channels = msg.has_num_output_channels() | |
443 ? msg.num_output_channels() | |
444 : msg.num_input_channels(); | |
445 } | |
446 | |
447 int output_sample_rate; | |
448 if (settings_.output_sample_rate_hz) { | |
449 output_sample_rate = *settings_.output_sample_rate_hz; | |
450 } else { | |
451 output_sample_rate = msg.has_output_sample_rate() ? msg.output_sample_rate() | |
452 : msg.sample_rate(); | |
453 } | |
454 | |
455 int num_reverse_output_channels; | |
456 if (settings_.reverse_output_num_channels) { | |
457 num_reverse_output_channels = *settings_.reverse_output_num_channels; | |
458 } else { | |
459 num_reverse_output_channels = msg.has_num_reverse_output_channels() | |
460 ? msg.num_reverse_output_channels() | |
461 : msg.num_reverse_channels(); | |
462 } | |
463 | |
464 int reverse_output_sample_rate; | |
465 if (settings_.reverse_output_sample_rate_hz) { | |
466 reverse_output_sample_rate = *settings_.reverse_output_sample_rate_hz; | |
467 } else { | |
468 reverse_output_sample_rate = msg.has_reverse_output_sample_rate() | |
469 ? msg.reverse_output_sample_rate() | |
470 : msg.reverse_sample_rate(); | |
471 } | |
472 | |
473 SetupBuffersConfigsOutputs( | |
474 msg.sample_rate(), output_sample_rate, msg.reverse_sample_rate(), | |
475 reverse_output_sample_rate, msg.num_input_channels(), num_output_channels, | |
476 msg.num_reverse_channels(), num_reverse_output_channels); | |
477 } | |
478 | |
479 void AecDumpBasedSimulator::HandleMessage( | |
480 const webrtc::audioproc::Stream& msg) { | |
481 PrepareProcessStreamCall(msg); | |
482 ProcessStream(interface_used_ == InterfaceType::kFixedInterface); | |
483 VerifyProcessStreamBitExactness(msg); | |
484 } | |
485 | |
486 void AecDumpBasedSimulator::HandleMessage( | |
487 const webrtc::audioproc::ReverseStream& msg) { | |
488 PrepareReverseProcessStreamCall(msg); | |
489 ProcessReverseStream(interface_used_ == InterfaceType::kFixedInterface); | |
490 } | |
491 | |
492 } // namespace test | |
493 } // namespace webrtc | |
OLD | NEW |