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