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 "modules/audio_processing/test/aec_dump_based_simulator.h"
12
13 #include <iostream>
14 #include <memory>
15
16 #include "modules/audio_processing/echo_control_mobile_impl.h"
17 #include "modules/audio_processing/logging/apm_data_dumper.h"
18 #include "modules/audio_processing/test/aec_dump_based_simulator.h"
19 #include "modules/audio_processing/test/protobuf_utils.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "rtc_base/numerics/safe_conversions.h"
23
24 namespace webrtc {
25 namespace test {
26 namespace {
27
28 // Verify output bitexactness for the fixed interface.
29 // TODO(peah): Check whether it would make sense to add a threshold
30 // to use for checking the bitexactness in a soft manner.
VerifyFixedBitExactness(const webrtc::audioproc::Stream & msg,const Int16Frame & frame)31 bool VerifyFixedBitExactness(const webrtc::audioproc::Stream& msg,
32 const Int16Frame& frame) {
33 if (sizeof(frame.data[0]) * frame.data.size() != msg.output_data().size()) {
34 return false;
35 } else {
36 const int16_t* frame_data = frame.data.data();
37 for (int k = 0; k < frame.num_channels * frame.samples_per_channel; ++k) {
38 if (msg.output_data().data()[k] != frame_data[k]) {
39 return false;
40 }
41 }
42 }
43 return true;
44 }
45
46 // Verify output bitexactness for the float interface.
VerifyFloatBitExactness(const webrtc::audioproc::Stream & msg,const StreamConfig & out_config,const ChannelBuffer<float> & out_buf)47 bool VerifyFloatBitExactness(const webrtc::audioproc::Stream& msg,
48 const StreamConfig& out_config,
49 const ChannelBuffer<float>& out_buf) {
50 if (static_cast<size_t>(msg.output_channel_size()) !=
51 out_config.num_channels() ||
52 msg.output_channel(0).size() != out_config.num_frames()) {
53 return false;
54 } else {
55 for (int ch = 0; ch < msg.output_channel_size(); ++ch) {
56 for (size_t sample = 0; sample < out_config.num_frames(); ++sample) {
57 if (msg.output_channel(ch).data()[sample] !=
58 out_buf.channels()[ch][sample]) {
59 return false;
60 }
61 }
62 }
63 }
64 return true;
65 }
66
67 // Selectively reads the next proto-buf message from dump-file or string input.
68 // Returns a bool indicating whether a new message was available.
ReadNextMessage(bool use_dump_file,FILE * dump_input_file,std::stringstream & input,webrtc::audioproc::Event & event_msg)69 bool ReadNextMessage(bool use_dump_file,
70 FILE* dump_input_file,
71 std::stringstream& input,
72 webrtc::audioproc::Event& event_msg) {
73 if (use_dump_file) {
74 return ReadMessageFromFile(dump_input_file, &event_msg);
75 }
76 return ReadMessageFromString(&input, &event_msg);
77 }
78
79 } // namespace
80
AecDumpBasedSimulator(const SimulationSettings & settings,rtc::scoped_refptr<AudioProcessing> audio_processing,std::unique_ptr<AudioProcessingBuilder> ap_builder)81 AecDumpBasedSimulator::AecDumpBasedSimulator(
82 const SimulationSettings& settings,
83 rtc::scoped_refptr<AudioProcessing> audio_processing,
84 std::unique_ptr<AudioProcessingBuilder> ap_builder)
85 : AudioProcessingSimulator(settings,
86 std::move(audio_processing),
87 std::move(ap_builder)) {
88 MaybeOpenCallOrderFile();
89 }
90
91 AecDumpBasedSimulator::~AecDumpBasedSimulator() = default;
92
PrepareProcessStreamCall(const webrtc::audioproc::Stream & msg)93 void AecDumpBasedSimulator::PrepareProcessStreamCall(
94 const webrtc::audioproc::Stream& msg) {
95 if (msg.has_input_data()) {
96 // Fixed interface processing.
97 // Verify interface invariance.
98 RTC_CHECK(interface_used_ == InterfaceType::kFixedInterface ||
99 interface_used_ == InterfaceType::kNotSpecified);
100 interface_used_ = InterfaceType::kFixedInterface;
101
102 // Populate input buffer.
103 RTC_CHECK_EQ(sizeof(fwd_frame_.data[0]) * fwd_frame_.data.size(),
104 msg.input_data().size());
105 memcpy(fwd_frame_.data.data(), msg.input_data().data(),
106 msg.input_data().size());
107 } else {
108 // Float interface processing.
109 // Verify interface invariance.
110 RTC_CHECK(interface_used_ == InterfaceType::kFloatInterface ||
111 interface_used_ == InterfaceType::kNotSpecified);
112 interface_used_ = InterfaceType::kFloatInterface;
113
114 RTC_CHECK_EQ(in_buf_->num_channels(),
115 static_cast<size_t>(msg.input_channel_size()));
116
117 // Populate input buffer.
118 for (size_t i = 0; i < in_buf_->num_channels(); ++i) {
119 RTC_CHECK_EQ(in_buf_->num_frames() * sizeof(*in_buf_->channels()[i]),
120 msg.input_channel(i).size());
121 std::memcpy(in_buf_->channels()[i], msg.input_channel(i).data(),
122 msg.input_channel(i).size());
123 }
124 }
125
126 if (artificial_nearend_buffer_reader_) {
127 if (artificial_nearend_buffer_reader_->Read(
128 artificial_nearend_buf_.get())) {
129 if (msg.has_input_data()) {
130 int16_t* fwd_frame_data = fwd_frame_.data.data();
131 for (size_t k = 0; k < in_buf_->num_frames(); ++k) {
132 fwd_frame_data[k] = rtc::saturated_cast<int16_t>(
133 fwd_frame_data[k] +
134 static_cast<int16_t>(32767 *
135 artificial_nearend_buf_->channels()[0][k]));
136 }
137 } else {
138 for (int i = 0; i < msg.input_channel_size(); ++i) {
139 for (size_t k = 0; k < in_buf_->num_frames(); ++k) {
140 in_buf_->channels()[i][k] +=
141 artificial_nearend_buf_->channels()[0][k];
142 in_buf_->channels()[i][k] = std::min(
143 32767.f, std::max(-32768.f, in_buf_->channels()[i][k]));
144 }
145 }
146 }
147 } else {
148 if (!artificial_nearend_eof_reported_) {
149 std::cout << "The artificial nearend file ended before the recording.";
150 artificial_nearend_eof_reported_ = true;
151 }
152 }
153 }
154
155 if (!settings_.use_stream_delay || *settings_.use_stream_delay) {
156 if (!settings_.stream_delay) {
157 if (msg.has_delay()) {
158 RTC_CHECK_EQ(AudioProcessing::kNoError,
159 ap_->set_stream_delay_ms(msg.delay()));
160 }
161 } else {
162 RTC_CHECK_EQ(AudioProcessing::kNoError,
163 ap_->set_stream_delay_ms(*settings_.stream_delay));
164 }
165 }
166
167 if (settings_.override_key_pressed.has_value()) {
168 // Key pressed state overridden.
169 ap_->set_stream_key_pressed(*settings_.override_key_pressed);
170 } else {
171 // Set the recorded key pressed state.
172 if (msg.has_keypress()) {
173 ap_->set_stream_key_pressed(msg.keypress());
174 }
175 }
176
177 // Set the applied input level if available.
178 aec_dump_applied_input_level_ =
179 msg.has_applied_input_volume()
180 ? absl::optional<int>(msg.applied_input_volume())
181 : absl::nullopt;
182 }
183
VerifyProcessStreamBitExactness(const webrtc::audioproc::Stream & msg)184 void AecDumpBasedSimulator::VerifyProcessStreamBitExactness(
185 const webrtc::audioproc::Stream& msg) {
186 if (bitexact_output_) {
187 if (interface_used_ == InterfaceType::kFixedInterface) {
188 bitexact_output_ = VerifyFixedBitExactness(msg, fwd_frame_);
189 } else {
190 bitexact_output_ = VerifyFloatBitExactness(msg, out_config_, *out_buf_);
191 }
192 }
193 }
194
PrepareReverseProcessStreamCall(const webrtc::audioproc::ReverseStream & msg)195 void AecDumpBasedSimulator::PrepareReverseProcessStreamCall(
196 const webrtc::audioproc::ReverseStream& msg) {
197 if (msg.has_data()) {
198 // Fixed interface processing.
199 // Verify interface invariance.
200 RTC_CHECK(interface_used_ == InterfaceType::kFixedInterface ||
201 interface_used_ == InterfaceType::kNotSpecified);
202 interface_used_ = InterfaceType::kFixedInterface;
203
204 // Populate input buffer.
205 RTC_CHECK_EQ(sizeof(rev_frame_.data[0]) * rev_frame_.data.size(),
206 msg.data().size());
207 memcpy(rev_frame_.data.data(), msg.data().data(), msg.data().size());
208 } else {
209 // Float interface processing.
210 // Verify interface invariance.
211 RTC_CHECK(interface_used_ == InterfaceType::kFloatInterface ||
212 interface_used_ == InterfaceType::kNotSpecified);
213 interface_used_ = InterfaceType::kFloatInterface;
214
215 RTC_CHECK_EQ(reverse_in_buf_->num_channels(),
216 static_cast<size_t>(msg.channel_size()));
217
218 // Populate input buffer.
219 for (int i = 0; i < msg.channel_size(); ++i) {
220 RTC_CHECK_EQ(reverse_in_buf_->num_frames() *
221 sizeof(*reverse_in_buf_->channels()[i]),
222 msg.channel(i).size());
223 std::memcpy(reverse_in_buf_->channels()[i], msg.channel(i).data(),
224 msg.channel(i).size());
225 }
226 }
227 }
228
Process()229 void AecDumpBasedSimulator::Process() {
230 ConfigureAudioProcessor();
231
232 if (settings_.artificial_nearend_filename) {
233 std::unique_ptr<WavReader> artificial_nearend_file(
234 new WavReader(settings_.artificial_nearend_filename->c_str()));
235
236 RTC_CHECK_EQ(1, artificial_nearend_file->num_channels())
237 << "Only mono files for the artificial nearend are supported, "
238 "reverted to not using the artificial nearend file";
239
240 const int sample_rate_hz = artificial_nearend_file->sample_rate();
241 artificial_nearend_buffer_reader_.reset(
242 new ChannelBufferWavReader(std::move(artificial_nearend_file)));
243 artificial_nearend_buf_.reset(new ChannelBuffer<float>(
244 rtc::CheckedDivExact(sample_rate_hz, kChunksPerSecond), 1));
245 }
246
247 const bool use_dump_file = !settings_.aec_dump_input_string.has_value();
248 std::stringstream input;
249 if (use_dump_file) {
250 dump_input_file_ =
251 OpenFile(settings_.aec_dump_input_filename->c_str(), "rb");
252 } else {
253 input << settings_.aec_dump_input_string.value();
254 }
255
256 webrtc::audioproc::Event event_msg;
257 int capture_frames_since_init = 0;
258 int init_index = 0;
259 while (ReadNextMessage(use_dump_file, dump_input_file_, input, event_msg)) {
260 SelectivelyToggleDataDumping(init_index, capture_frames_since_init);
261 HandleEvent(event_msg, capture_frames_since_init, init_index);
262
263 // Perfom an early exit if the init block to process has been fully
264 // processed
265 if (finished_processing_specified_init_block_) {
266 break;
267 }
268 RTC_CHECK(!settings_.init_to_process ||
269 *settings_.init_to_process >= init_index);
270 }
271
272 if (use_dump_file) {
273 fclose(dump_input_file_);
274 }
275
276 DetachAecDump();
277 }
278
Analyze()279 void AecDumpBasedSimulator::Analyze() {
280 const bool use_dump_file = !settings_.aec_dump_input_string.has_value();
281 std::stringstream input;
282 if (use_dump_file) {
283 dump_input_file_ =
284 OpenFile(settings_.aec_dump_input_filename->c_str(), "rb");
285 } else {
286 input << settings_.aec_dump_input_string.value();
287 }
288
289 webrtc::audioproc::Event event_msg;
290 int num_capture_frames = 0;
291 int num_render_frames = 0;
292 int init_index = 0;
293 while (ReadNextMessage(use_dump_file, dump_input_file_, input, event_msg)) {
294 if (event_msg.type() == webrtc::audioproc::Event::INIT) {
295 ++init_index;
296 constexpr float kNumFramesPerSecond = 100.f;
297 float capture_time_seconds = num_capture_frames / kNumFramesPerSecond;
298 float render_time_seconds = num_render_frames / kNumFramesPerSecond;
299
300 std::cout << "Inits:" << std::endl;
301 std::cout << init_index << ": -->" << std::endl;
302 std::cout << " Time:" << std::endl;
303 std::cout << " Capture: " << capture_time_seconds << " s ("
304 << num_capture_frames << " frames) " << std::endl;
305 std::cout << " Render: " << render_time_seconds << " s ("
306 << num_render_frames << " frames) " << std::endl;
307 } else if (event_msg.type() == webrtc::audioproc::Event::STREAM) {
308 ++num_capture_frames;
309 } else if (event_msg.type() == webrtc::audioproc::Event::REVERSE_STREAM) {
310 ++num_render_frames;
311 }
312 }
313
314 if (use_dump_file) {
315 fclose(dump_input_file_);
316 }
317 }
318
HandleEvent(const webrtc::audioproc::Event & event_msg,int & capture_frames_since_init,int & init_index)319 void AecDumpBasedSimulator::HandleEvent(
320 const webrtc::audioproc::Event& event_msg,
321 int& capture_frames_since_init,
322 int& init_index) {
323 switch (event_msg.type()) {
324 case webrtc::audioproc::Event::INIT:
325 RTC_CHECK(event_msg.has_init());
326 ++init_index;
327 capture_frames_since_init = 0;
328 HandleMessage(event_msg.init(), init_index);
329 break;
330 case webrtc::audioproc::Event::STREAM:
331 RTC_CHECK(event_msg.has_stream());
332 ++capture_frames_since_init;
333 HandleMessage(event_msg.stream());
334 break;
335 case webrtc::audioproc::Event::REVERSE_STREAM:
336 RTC_CHECK(event_msg.has_reverse_stream());
337 HandleMessage(event_msg.reverse_stream());
338 break;
339 case webrtc::audioproc::Event::CONFIG:
340 RTC_CHECK(event_msg.has_config());
341 HandleMessage(event_msg.config());
342 break;
343 case webrtc::audioproc::Event::RUNTIME_SETTING:
344 HandleMessage(event_msg.runtime_setting());
345 break;
346 case webrtc::audioproc::Event::UNKNOWN_EVENT:
347 RTC_CHECK_NOTREACHED();
348 }
349 }
350
HandleMessage(const webrtc::audioproc::Config & msg)351 void AecDumpBasedSimulator::HandleMessage(
352 const webrtc::audioproc::Config& msg) {
353 if (settings_.use_verbose_logging) {
354 std::cout << "Config at frame:" << std::endl;
355 std::cout << " Forward: " << get_num_process_stream_calls() << std::endl;
356 std::cout << " Reverse: " << get_num_reverse_process_stream_calls()
357 << std::endl;
358 }
359
360 if (!settings_.discard_all_settings_in_aecdump) {
361 if (settings_.use_verbose_logging) {
362 std::cout << "Setting used in config:" << std::endl;
363 }
364 AudioProcessing::Config apm_config = ap_->GetConfig();
365
366 if (msg.has_aec_enabled() || settings_.use_aec) {
367 bool enable = settings_.use_aec ? *settings_.use_aec : msg.aec_enabled();
368 apm_config.echo_canceller.enabled = enable;
369 if (settings_.use_verbose_logging) {
370 std::cout << " aec_enabled: " << (enable ? "true" : "false")
371 << std::endl;
372 }
373 }
374
375 if (msg.has_aecm_enabled() || settings_.use_aecm) {
376 bool enable =
377 settings_.use_aecm ? *settings_.use_aecm : msg.aecm_enabled();
378 apm_config.echo_canceller.enabled |= enable;
379 apm_config.echo_canceller.mobile_mode = enable;
380 if (settings_.use_verbose_logging) {
381 std::cout << " aecm_enabled: " << (enable ? "true" : "false")
382 << std::endl;
383 }
384 }
385
386 if (msg.has_aecm_comfort_noise_enabled() &&
387 msg.aecm_comfort_noise_enabled()) {
388 RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM comfort noise";
389 }
390
391 if (msg.has_aecm_routing_mode() &&
392 static_cast<webrtc::EchoControlMobileImpl::RoutingMode>(
393 msg.aecm_routing_mode()) != EchoControlMobileImpl::kSpeakerphone) {
394 RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AECM routing mode: "
395 << msg.aecm_routing_mode();
396 }
397
398 if (msg.has_agc_enabled() || settings_.use_agc) {
399 bool enable = settings_.use_agc ? *settings_.use_agc : msg.agc_enabled();
400 apm_config.gain_controller1.enabled = enable;
401 if (settings_.use_verbose_logging) {
402 std::cout << " agc_enabled: " << (enable ? "true" : "false")
403 << std::endl;
404 }
405 }
406
407 if (msg.has_agc_mode() || settings_.agc_mode) {
408 int mode = settings_.agc_mode ? *settings_.agc_mode : msg.agc_mode();
409 apm_config.gain_controller1.mode =
410 static_cast<webrtc::AudioProcessing::Config::GainController1::Mode>(
411 mode);
412 if (settings_.use_verbose_logging) {
413 std::cout << " agc_mode: " << mode << std::endl;
414 }
415 }
416
417 if (msg.has_agc_limiter_enabled() || settings_.use_agc_limiter) {
418 bool enable = settings_.use_agc_limiter ? *settings_.use_agc_limiter
419 : msg.agc_limiter_enabled();
420 apm_config.gain_controller1.enable_limiter = enable;
421 if (settings_.use_verbose_logging) {
422 std::cout << " agc_limiter_enabled: " << (enable ? "true" : "false")
423 << std::endl;
424 }
425 }
426
427 if (settings_.use_agc2) {
428 bool enable = *settings_.use_agc2;
429 apm_config.gain_controller2.enabled = enable;
430 if (settings_.agc2_fixed_gain_db) {
431 apm_config.gain_controller2.fixed_digital.gain_db =
432 *settings_.agc2_fixed_gain_db;
433 }
434 if (settings_.use_verbose_logging) {
435 std::cout << " agc2_enabled: " << (enable ? "true" : "false")
436 << std::endl;
437 }
438 }
439
440 if (msg.has_noise_robust_agc_enabled()) {
441 apm_config.gain_controller1.analog_gain_controller.enabled =
442 settings_.use_analog_agc ? *settings_.use_analog_agc
443 : msg.noise_robust_agc_enabled();
444 if (settings_.use_verbose_logging) {
445 std::cout << " noise_robust_agc_enabled: "
446 << (msg.noise_robust_agc_enabled() ? "true" : "false")
447 << std::endl;
448 }
449 }
450
451 if (msg.has_transient_suppression_enabled() || settings_.use_ts) {
452 bool enable = settings_.use_ts ? *settings_.use_ts
453 : msg.transient_suppression_enabled();
454 apm_config.transient_suppression.enabled = enable;
455 if (settings_.use_verbose_logging) {
456 std::cout << " transient_suppression_enabled: "
457 << (enable ? "true" : "false") << std::endl;
458 }
459 }
460
461 if (msg.has_hpf_enabled() || settings_.use_hpf) {
462 bool enable = settings_.use_hpf ? *settings_.use_hpf : msg.hpf_enabled();
463 apm_config.high_pass_filter.enabled = enable;
464 if (settings_.use_verbose_logging) {
465 std::cout << " hpf_enabled: " << (enable ? "true" : "false")
466 << std::endl;
467 }
468 }
469
470 if (msg.has_ns_enabled() || settings_.use_ns) {
471 bool enable = settings_.use_ns ? *settings_.use_ns : msg.ns_enabled();
472 apm_config.noise_suppression.enabled = enable;
473 if (settings_.use_verbose_logging) {
474 std::cout << " ns_enabled: " << (enable ? "true" : "false")
475 << std::endl;
476 }
477 }
478
479 if (msg.has_ns_level() || settings_.ns_level) {
480 int level = settings_.ns_level ? *settings_.ns_level : msg.ns_level();
481 apm_config.noise_suppression.level =
482 static_cast<AudioProcessing::Config::NoiseSuppression::Level>(level);
483 if (settings_.use_verbose_logging) {
484 std::cout << " ns_level: " << level << std::endl;
485 }
486 }
487
488 if (msg.has_pre_amplifier_enabled() || settings_.use_pre_amplifier) {
489 const bool enable = settings_.use_pre_amplifier
490 ? *settings_.use_pre_amplifier
491 : msg.pre_amplifier_enabled();
492 apm_config.pre_amplifier.enabled = enable;
493 }
494
495 if (msg.has_pre_amplifier_fixed_gain_factor() ||
496 settings_.pre_amplifier_gain_factor) {
497 const float gain = settings_.pre_amplifier_gain_factor
498 ? *settings_.pre_amplifier_gain_factor
499 : msg.pre_amplifier_fixed_gain_factor();
500 apm_config.pre_amplifier.fixed_gain_factor = gain;
501 }
502
503 if (settings_.use_verbose_logging && msg.has_experiments_description() &&
504 !msg.experiments_description().empty()) {
505 std::cout << " experiments not included by default in the simulation: "
506 << msg.experiments_description() << std::endl;
507 }
508
509 ap_->ApplyConfig(apm_config);
510 }
511 }
512
HandleMessage(const webrtc::audioproc::Init & msg,int init_index)513 void AecDumpBasedSimulator::HandleMessage(const webrtc::audioproc::Init& msg,
514 int init_index) {
515 RTC_CHECK(msg.has_sample_rate());
516 RTC_CHECK(msg.has_num_input_channels());
517 RTC_CHECK(msg.has_num_reverse_channels());
518 RTC_CHECK(msg.has_reverse_sample_rate());
519
520 // Do not perform the init if the init block to process is fully processed
521 if (settings_.init_to_process && *settings_.init_to_process < init_index) {
522 finished_processing_specified_init_block_ = true;
523 }
524
525 MaybeOpenCallOrderFile();
526
527 if (settings_.use_verbose_logging) {
528 std::cout << "Init at frame:" << std::endl;
529 std::cout << " Forward: " << get_num_process_stream_calls() << std::endl;
530 std::cout << " Reverse: " << get_num_reverse_process_stream_calls()
531 << std::endl;
532 }
533
534 int num_output_channels;
535 if (settings_.output_num_channels) {
536 num_output_channels = *settings_.output_num_channels;
537 } else {
538 num_output_channels = msg.has_num_output_channels()
539 ? msg.num_output_channels()
540 : msg.num_input_channels();
541 }
542
543 int output_sample_rate;
544 if (settings_.output_sample_rate_hz) {
545 output_sample_rate = *settings_.output_sample_rate_hz;
546 } else {
547 output_sample_rate = msg.has_output_sample_rate() ? msg.output_sample_rate()
548 : msg.sample_rate();
549 }
550
551 int num_reverse_output_channels;
552 if (settings_.reverse_output_num_channels) {
553 num_reverse_output_channels = *settings_.reverse_output_num_channels;
554 } else {
555 num_reverse_output_channels = msg.has_num_reverse_output_channels()
556 ? msg.num_reverse_output_channels()
557 : msg.num_reverse_channels();
558 }
559
560 int reverse_output_sample_rate;
561 if (settings_.reverse_output_sample_rate_hz) {
562 reverse_output_sample_rate = *settings_.reverse_output_sample_rate_hz;
563 } else {
564 reverse_output_sample_rate = msg.has_reverse_output_sample_rate()
565 ? msg.reverse_output_sample_rate()
566 : msg.reverse_sample_rate();
567 }
568
569 SetupBuffersConfigsOutputs(
570 msg.sample_rate(), output_sample_rate, msg.reverse_sample_rate(),
571 reverse_output_sample_rate, msg.num_input_channels(), num_output_channels,
572 msg.num_reverse_channels(), num_reverse_output_channels);
573 }
574
HandleMessage(const webrtc::audioproc::Stream & msg)575 void AecDumpBasedSimulator::HandleMessage(
576 const webrtc::audioproc::Stream& msg) {
577 if (call_order_output_file_) {
578 *call_order_output_file_ << "c";
579 }
580 PrepareProcessStreamCall(msg);
581 ProcessStream(interface_used_ == InterfaceType::kFixedInterface);
582 VerifyProcessStreamBitExactness(msg);
583 }
584
HandleMessage(const webrtc::audioproc::ReverseStream & msg)585 void AecDumpBasedSimulator::HandleMessage(
586 const webrtc::audioproc::ReverseStream& msg) {
587 if (call_order_output_file_) {
588 *call_order_output_file_ << "r";
589 }
590 PrepareReverseProcessStreamCall(msg);
591 ProcessReverseStream(interface_used_ == InterfaceType::kFixedInterface);
592 }
593
HandleMessage(const webrtc::audioproc::RuntimeSetting & msg)594 void AecDumpBasedSimulator::HandleMessage(
595 const webrtc::audioproc::RuntimeSetting& msg) {
596 RTC_CHECK(ap_.get());
597 if (msg.has_capture_pre_gain()) {
598 // Handle capture pre-gain runtime setting only if not overridden.
599 const bool pre_amplifier_overridden =
600 (!settings_.use_pre_amplifier || *settings_.use_pre_amplifier) &&
601 !settings_.pre_amplifier_gain_factor;
602 const bool capture_level_adjustment_overridden =
603 (!settings_.use_capture_level_adjustment ||
604 *settings_.use_capture_level_adjustment) &&
605 !settings_.pre_gain_factor;
606 if (pre_amplifier_overridden || capture_level_adjustment_overridden) {
607 ap_->SetRuntimeSetting(
608 AudioProcessing::RuntimeSetting::CreateCapturePreGain(
609 msg.capture_pre_gain()));
610 }
611 } else if (msg.has_capture_post_gain()) {
612 // Handle capture post-gain runtime setting only if not overridden.
613 if ((!settings_.use_capture_level_adjustment ||
614 *settings_.use_capture_level_adjustment) &&
615 !settings_.post_gain_factor) {
616 ap_->SetRuntimeSetting(
617 AudioProcessing::RuntimeSetting::CreateCapturePreGain(
618 msg.capture_pre_gain()));
619 }
620 } else if (msg.has_capture_fixed_post_gain()) {
621 // Handle capture fixed-post-gain runtime setting only if not overridden.
622 if ((!settings_.use_agc2 || *settings_.use_agc2) &&
623 !settings_.agc2_fixed_gain_db) {
624 ap_->SetRuntimeSetting(
625 AudioProcessing::RuntimeSetting::CreateCaptureFixedPostGain(
626 msg.capture_fixed_post_gain()));
627 }
628 } else if (msg.has_playout_volume_change()) {
629 ap_->SetRuntimeSetting(
630 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(
631 msg.playout_volume_change()));
632 } else if (msg.has_playout_audio_device_change()) {
633 ap_->SetRuntimeSetting(
634 AudioProcessing::RuntimeSetting::CreatePlayoutAudioDeviceChange(
635 {msg.playout_audio_device_change().id(),
636 msg.playout_audio_device_change().max_volume()}));
637 } else if (msg.has_capture_output_used()) {
638 ap_->SetRuntimeSetting(
639 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
640 msg.capture_output_used()));
641 }
642 }
643
MaybeOpenCallOrderFile()644 void AecDumpBasedSimulator::MaybeOpenCallOrderFile() {
645 if (settings_.call_order_output_filename.has_value()) {
646 const std::string filename = settings_.store_intermediate_output
647 ? *settings_.call_order_output_filename +
648 "_" +
649 std::to_string(output_reset_counter_)
650 : *settings_.call_order_output_filename;
651 call_order_output_file_ = std::make_unique<std::ofstream>(filename);
652 }
653 }
654
655 } // namespace test
656 } // namespace webrtc
657