| 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 #include <math.h> |  | 
|    12 #include <stdio.h> |  | 
|    13 #include <string.h> |  | 
|    14 #ifdef WEBRTC_ANDROID |  | 
|    15 #include <sys/stat.h> |  | 
|    16 #endif |  | 
|    17  |  | 
|    18 #include <algorithm> |  | 
|    19 #include <memory> |  | 
|    20  |  | 
|    21 #include "webrtc/base/format_macros.h" |  | 
|    22 #include "webrtc/base/ignore_wundef.h" |  | 
|    23 #include "webrtc/base/timeutils.h" |  | 
|    24 #include "webrtc/modules/audio_processing/include/audio_processing.h" |  | 
|    25 #include "webrtc/modules/audio_processing/include/config.h" |  | 
|    26 #include "webrtc/modules/audio_processing/test/protobuf_utils.h" |  | 
|    27 #include "webrtc/modules/audio_processing/test/test_utils.h" |  | 
|    28 #include "webrtc/modules/include/module_common_types.h" |  | 
|    29 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h" |  | 
|    30 #include "webrtc/test/gtest.h" |  | 
|    31 #include "webrtc/test/testsupport/fileutils.h" |  | 
|    32 #include "webrtc/test/testsupport/perf_test.h" |  | 
|    33  |  | 
|    34 RTC_PUSH_IGNORING_WUNDEF() |  | 
|    35 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD |  | 
|    36 #include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h" |  | 
|    37 #else |  | 
|    38 #include "webrtc/modules/audio_processing/debug.pb.h" |  | 
|    39 #endif |  | 
|    40 RTC_POP_IGNORING_WUNDEF() |  | 
|    41  |  | 
|    42 namespace webrtc { |  | 
|    43  |  | 
|    44 using webrtc::audioproc::Event; |  | 
|    45 using webrtc::audioproc::Init; |  | 
|    46 using webrtc::audioproc::ReverseStream; |  | 
|    47 using webrtc::audioproc::Stream; |  | 
|    48  |  | 
|    49 namespace { |  | 
|    50  |  | 
|    51 void PrintStat(const AudioProcessing::Statistic& stat) { |  | 
|    52   printf("%d, %d, %d\n", stat.average, |  | 
|    53                          stat.maximum, |  | 
|    54                          stat.minimum); |  | 
|    55 } |  | 
|    56  |  | 
|    57 void usage() { |  | 
|    58   printf( |  | 
|    59   "Usage: process_test [options] [-pb PROTOBUF_FILE]\n" |  | 
|    60   "  [-ir REVERSE_FILE] [-i PRIMARY_FILE] [-o OUT_FILE]\n"); |  | 
|    61   printf( |  | 
|    62   "process_test is a test application for AudioProcessing.\n\n" |  | 
|    63   "When a protobuf debug file is available, specify it with -pb. Alternately,\n" |  | 
|    64   "when -ir or -i is used, the specified files will be processed directly in\n" |  | 
|    65   "a simulation mode. Otherwise the full set of legacy test files is expected\n" |  | 
|    66   "to be present in the working directory. OUT_FILE should be specified\n" |  | 
|    67   "without extension to support both raw and wav output.\n\n"); |  | 
|    68   printf("Options\n"); |  | 
|    69   printf("General configuration (only used for the simulation mode):\n"); |  | 
|    70   printf("  -fs SAMPLE_RATE_HZ\n"); |  | 
|    71   printf("  -ch CHANNELS_IN CHANNELS_OUT\n"); |  | 
|    72   printf("  -rch REVERSE_CHANNELS\n"); |  | 
|    73   printf("\n"); |  | 
|    74   printf("Component configuration:\n"); |  | 
|    75   printf( |  | 
|    76   "All components are disabled by default. Each block below begins with a\n" |  | 
|    77   "flag to enable the component with default settings. The subsequent flags\n" |  | 
|    78   "in the block are used to provide configuration settings.\n"); |  | 
|    79   printf("\n  -aec     Echo cancellation\n"); |  | 
|    80   printf("  --drift_compensation\n"); |  | 
|    81   printf("  --no_drift_compensation\n"); |  | 
|    82   printf("  --no_echo_metrics\n"); |  | 
|    83   printf("  --no_delay_logging\n"); |  | 
|    84   printf("  --aec_suppression_level LEVEL  [0 - 2]\n"); |  | 
|    85   printf("  --extended_filter\n"); |  | 
|    86   printf("  --no_reported_delay\n"); |  | 
|    87   printf("  --aec3\n"); |  | 
|    88   printf("  --refined_adaptive_filter\n"); |  | 
|    89   printf("\n  -aecm    Echo control mobile\n"); |  | 
|    90   printf("  --aecm_echo_path_in_file FILE\n"); |  | 
|    91   printf("  --aecm_echo_path_out_file FILE\n"); |  | 
|    92   printf("  --no_comfort_noise\n"); |  | 
|    93   printf("  --routing_mode MODE  [0 - 4]\n"); |  | 
|    94   printf("\n  -agc     Gain control\n"); |  | 
|    95   printf("  --analog\n"); |  | 
|    96   printf("  --adaptive_digital\n"); |  | 
|    97   printf("  --fixed_digital\n"); |  | 
|    98   printf("  --target_level LEVEL\n"); |  | 
|    99   printf("  --compression_gain GAIN\n"); |  | 
|   100   printf("  --limiter\n"); |  | 
|   101   printf("  --no_limiter\n"); |  | 
|   102   printf("\n  -hpf     High pass filter\n"); |  | 
|   103   printf("\n  -ns      Noise suppression\n"); |  | 
|   104   printf("  --ns_low\n"); |  | 
|   105   printf("  --ns_moderate\n"); |  | 
|   106   printf("  --ns_high\n"); |  | 
|   107   printf("  --ns_very_high\n"); |  | 
|   108   printf("  --ns_prob_file FILE\n"); |  | 
|   109   printf("\n  -vad     Voice activity detection\n"); |  | 
|   110   printf("  --vad_out_file FILE\n"); |  | 
|   111   printf("\n  -expns   Experimental noise suppression\n"); |  | 
|   112   printf("\n Level metrics (enabled by default)\n"); |  | 
|   113   printf("  --no_level_metrics\n"); |  | 
|   114   printf("  --level_control\n"); |  | 
|   115   printf("\n"); |  | 
|   116   printf("Modifiers:\n"); |  | 
|   117   printf("  --noasm            Disable SSE optimization.\n"); |  | 
|   118   printf("  --add_delay DELAY  Add DELAY ms to input value.\n"); |  | 
|   119   printf("  --delay DELAY      Override input delay with DELAY ms.\n"); |  | 
|   120   printf("  --perf             Measure performance.\n"); |  | 
|   121   printf("  --quiet            Suppress text output.\n"); |  | 
|   122   printf("  --no_progress      Suppress progress.\n"); |  | 
|   123   printf("  --raw_output       Raw output instead of WAV file.\n"); |  | 
|   124   printf("  --debug_file FILE  Dump a debug recording.\n"); |  | 
|   125 } |  | 
|   126  |  | 
|   127 static float MicLevel2Gain(int level) { |  | 
|   128   return pow(10.0f, ((level - 127.0f) / 128.0f * 40.0f) / 20.0f); |  | 
|   129 } |  | 
|   130  |  | 
|   131 static void SimulateMic(int mic_level, AudioFrame* frame) { |  | 
|   132   mic_level = std::min(std::max(mic_level, 0), 255); |  | 
|   133   float mic_gain = MicLevel2Gain(mic_level); |  | 
|   134   int num_samples = frame->samples_per_channel_ * frame->num_channels_; |  | 
|   135   float v; |  | 
|   136   for (int n = 0; n < num_samples; n++) { |  | 
|   137     v = floor(frame->data_[n] * mic_gain + 0.5); |  | 
|   138     v = std::max(std::min(32767.0f, v), -32768.0f); |  | 
|   139     frame->data_[n] = static_cast<int16_t>(v); |  | 
|   140   } |  | 
|   141 } |  | 
|   142  |  | 
|   143 // void function for gtest. |  | 
|   144 void void_main(int argc, char* argv[]) { |  | 
|   145   if (argc > 1 && strcmp(argv[1], "--help") == 0) { |  | 
|   146     usage(); |  | 
|   147     return; |  | 
|   148   } |  | 
|   149  |  | 
|   150   if (argc < 2) { |  | 
|   151     printf("Did you mean to run without arguments?\n"); |  | 
|   152     printf("Try `process_test --help' for more information.\n\n"); |  | 
|   153   } |  | 
|   154  |  | 
|   155   std::unique_ptr<AudioProcessing> apm(AudioProcessing::Create()); |  | 
|   156   ASSERT_TRUE(apm.get() != NULL); |  | 
|   157  |  | 
|   158   const char* pb_filename = NULL; |  | 
|   159   const char* far_filename = NULL; |  | 
|   160   const char* near_filename = NULL; |  | 
|   161   std::string out_filename; |  | 
|   162   const char* vad_out_filename = NULL; |  | 
|   163   const char* ns_prob_filename = NULL; |  | 
|   164   const char* aecm_echo_path_in_filename = NULL; |  | 
|   165   const char* aecm_echo_path_out_filename = NULL; |  | 
|   166  |  | 
|   167   int32_t sample_rate_hz = 16000; |  | 
|   168  |  | 
|   169   size_t num_capture_input_channels = 1; |  | 
|   170   size_t num_capture_output_channels = 1; |  | 
|   171   size_t num_render_channels = 1; |  | 
|   172  |  | 
|   173   int samples_per_channel = sample_rate_hz / 100; |  | 
|   174  |  | 
|   175   bool simulating = false; |  | 
|   176   bool perf_testing = false; |  | 
|   177   bool verbose = true; |  | 
|   178   bool progress = true; |  | 
|   179   bool raw_output = false; |  | 
|   180   int extra_delay_ms = 0; |  | 
|   181   int override_delay_ms = 0; |  | 
|   182   Config config; |  | 
|   183   AudioProcessing::Config apm_config; |  | 
|   184  |  | 
|   185   ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(true)); |  | 
|   186   for (int i = 1; i < argc; i++) { |  | 
|   187     if (strcmp(argv[i], "-pb") == 0) { |  | 
|   188       i++; |  | 
|   189       ASSERT_LT(i, argc) << "Specify protobuf filename after -pb"; |  | 
|   190       pb_filename = argv[i]; |  | 
|   191  |  | 
|   192     } else if (strcmp(argv[i], "-ir") == 0) { |  | 
|   193       i++; |  | 
|   194       ASSERT_LT(i, argc) << "Specify filename after -ir"; |  | 
|   195       far_filename = argv[i]; |  | 
|   196       simulating = true; |  | 
|   197  |  | 
|   198     } else if (strcmp(argv[i], "-i") == 0) { |  | 
|   199       i++; |  | 
|   200       ASSERT_LT(i, argc) << "Specify filename after -i"; |  | 
|   201       near_filename = argv[i]; |  | 
|   202       simulating = true; |  | 
|   203  |  | 
|   204     } else if (strcmp(argv[i], "-o") == 0) { |  | 
|   205       i++; |  | 
|   206       ASSERT_LT(i, argc) << "Specify filename without extension after -o"; |  | 
|   207       out_filename = argv[i]; |  | 
|   208  |  | 
|   209     } else if (strcmp(argv[i], "-fs") == 0) { |  | 
|   210       i++; |  | 
|   211       ASSERT_LT(i, argc) << "Specify sample rate after -fs"; |  | 
|   212       ASSERT_EQ(1, sscanf(argv[i], "%d", &sample_rate_hz)); |  | 
|   213       samples_per_channel = sample_rate_hz / 100; |  | 
|   214  |  | 
|   215     } else if (strcmp(argv[i], "-ch") == 0) { |  | 
|   216       i++; |  | 
|   217       ASSERT_LT(i + 1, argc) << "Specify number of channels after -ch"; |  | 
|   218       ASSERT_EQ(1, sscanf(argv[i], "%" PRIuS, &num_capture_input_channels)); |  | 
|   219       i++; |  | 
|   220       ASSERT_EQ(1, sscanf(argv[i], "%" PRIuS, &num_capture_output_channels)); |  | 
|   221  |  | 
|   222     } else if (strcmp(argv[i], "-rch") == 0) { |  | 
|   223       i++; |  | 
|   224       ASSERT_LT(i, argc) << "Specify number of channels after -rch"; |  | 
|   225       ASSERT_EQ(1, sscanf(argv[i], "%" PRIuS, &num_render_channels)); |  | 
|   226  |  | 
|   227     } else if (strcmp(argv[i], "-aec") == 0) { |  | 
|   228       ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); |  | 
|   229       ASSERT_EQ(apm->kNoError, |  | 
|   230                 apm->echo_cancellation()->enable_metrics(true)); |  | 
|   231       ASSERT_EQ(apm->kNoError, |  | 
|   232                 apm->echo_cancellation()->enable_delay_logging(true)); |  | 
|   233  |  | 
|   234     } else if (strcmp(argv[i], "--drift_compensation") == 0) { |  | 
|   235       ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); |  | 
|   236       // TODO(ajm): this is enabled in the VQE test app by default. Investigate |  | 
|   237       //            why it can give better performance despite passing zeros. |  | 
|   238       ASSERT_EQ(apm->kNoError, |  | 
|   239                 apm->echo_cancellation()->enable_drift_compensation(true)); |  | 
|   240     } else if (strcmp(argv[i], "--no_drift_compensation") == 0) { |  | 
|   241       ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); |  | 
|   242       ASSERT_EQ(apm->kNoError, |  | 
|   243                 apm->echo_cancellation()->enable_drift_compensation(false)); |  | 
|   244  |  | 
|   245     } else if (strcmp(argv[i], "--no_echo_metrics") == 0) { |  | 
|   246       ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); |  | 
|   247       ASSERT_EQ(apm->kNoError, |  | 
|   248                 apm->echo_cancellation()->enable_metrics(false)); |  | 
|   249  |  | 
|   250     } else if (strcmp(argv[i], "--no_delay_logging") == 0) { |  | 
|   251       ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true)); |  | 
|   252       ASSERT_EQ(apm->kNoError, |  | 
|   253                 apm->echo_cancellation()->enable_delay_logging(false)); |  | 
|   254  |  | 
|   255     } else if (strcmp(argv[i], "--no_level_metrics") == 0) { |  | 
|   256       ASSERT_EQ(apm->kNoError, apm->level_estimator()->Enable(false)); |  | 
|   257  |  | 
|   258     } else if (strcmp(argv[i], "--aec_suppression_level") == 0) { |  | 
|   259       i++; |  | 
|   260       ASSERT_LT(i, argc) << "Specify level after --aec_suppression_level"; |  | 
|   261       int suppression_level; |  | 
|   262       ASSERT_EQ(1, sscanf(argv[i], "%d", &suppression_level)); |  | 
|   263       ASSERT_EQ(apm->kNoError, |  | 
|   264                 apm->echo_cancellation()->set_suppression_level( |  | 
|   265                     static_cast<webrtc::EchoCancellation::SuppressionLevel>( |  | 
|   266                         suppression_level))); |  | 
|   267  |  | 
|   268     } else if (strcmp(argv[i], "--level_control") == 0) { |  | 
|   269       apm_config.level_controller.enabled = true; |  | 
|   270     } else if (strcmp(argv[i], "--extended_filter") == 0) { |  | 
|   271       config.Set<ExtendedFilter>(new ExtendedFilter(true)); |  | 
|   272  |  | 
|   273     } else if (strcmp(argv[i], "--no_reported_delay") == 0) { |  | 
|   274       config.Set<DelayAgnostic>(new DelayAgnostic(true)); |  | 
|   275  |  | 
|   276     } else if (strcmp(argv[i], "--delay_agnostic") == 0) { |  | 
|   277       config.Set<DelayAgnostic>(new DelayAgnostic(true)); |  | 
|   278  |  | 
|   279     } else if (strcmp(argv[i], "--aec3") == 0) { |  | 
|   280       config.Set<EchoCanceller3>(new EchoCanceller3(true)); |  | 
|   281  |  | 
|   282     } else if (strcmp(argv[i], "--refined_adaptive_filter") == 0) { |  | 
|   283       config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(true)); |  | 
|   284  |  | 
|   285     } else if (strcmp(argv[i], "-aecm") == 0) { |  | 
|   286       ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true)); |  | 
|   287  |  | 
|   288     } else if (strcmp(argv[i], "--aecm_echo_path_in_file") == 0) { |  | 
|   289       i++; |  | 
|   290       ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_in_file"; |  | 
|   291       aecm_echo_path_in_filename = argv[i]; |  | 
|   292  |  | 
|   293     } else if (strcmp(argv[i], "--aecm_echo_path_out_file") == 0) { |  | 
|   294       i++; |  | 
|   295       ASSERT_LT(i, argc) << "Specify filename after --aecm_echo_path_out_file"; |  | 
|   296       aecm_echo_path_out_filename = argv[i]; |  | 
|   297  |  | 
|   298     } else if (strcmp(argv[i], "--no_comfort_noise") == 0) { |  | 
|   299       ASSERT_EQ(apm->kNoError, |  | 
|   300                 apm->echo_control_mobile()->enable_comfort_noise(false)); |  | 
|   301  |  | 
|   302     } else if (strcmp(argv[i], "--routing_mode") == 0) { |  | 
|   303       i++; |  | 
|   304       ASSERT_LT(i, argc) << "Specify mode after --routing_mode"; |  | 
|   305       int routing_mode; |  | 
|   306       ASSERT_EQ(1, sscanf(argv[i], "%d", &routing_mode)); |  | 
|   307       ASSERT_EQ(apm->kNoError, |  | 
|   308                 apm->echo_control_mobile()->set_routing_mode( |  | 
|   309                     static_cast<webrtc::EchoControlMobile::RoutingMode>( |  | 
|   310                         routing_mode))); |  | 
|   311  |  | 
|   312     } else if (strcmp(argv[i], "-agc") == 0) { |  | 
|   313       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   314  |  | 
|   315     } else if (strcmp(argv[i], "--analog") == 0) { |  | 
|   316       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   317       ASSERT_EQ(apm->kNoError, |  | 
|   318                 apm->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); |  | 
|   319  |  | 
|   320     } else if (strcmp(argv[i], "--adaptive_digital") == 0) { |  | 
|   321       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   322       ASSERT_EQ(apm->kNoError, |  | 
|   323                 apm->gain_control()->set_mode(GainControl::kAdaptiveDigital)); |  | 
|   324  |  | 
|   325     } else if (strcmp(argv[i], "--fixed_digital") == 0) { |  | 
|   326       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   327       ASSERT_EQ(apm->kNoError, |  | 
|   328                 apm->gain_control()->set_mode(GainControl::kFixedDigital)); |  | 
|   329  |  | 
|   330     } else if (strcmp(argv[i], "--target_level") == 0) { |  | 
|   331       i++; |  | 
|   332       int level; |  | 
|   333       ASSERT_EQ(1, sscanf(argv[i], "%d", &level)); |  | 
|   334  |  | 
|   335       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   336       ASSERT_EQ(apm->kNoError, |  | 
|   337                 apm->gain_control()->set_target_level_dbfs(level)); |  | 
|   338  |  | 
|   339     } else if (strcmp(argv[i], "--compression_gain") == 0) { |  | 
|   340       i++; |  | 
|   341       int gain; |  | 
|   342       ASSERT_EQ(1, sscanf(argv[i], "%d", &gain)); |  | 
|   343  |  | 
|   344       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   345       ASSERT_EQ(apm->kNoError, |  | 
|   346                 apm->gain_control()->set_compression_gain_db(gain)); |  | 
|   347  |  | 
|   348     } else if (strcmp(argv[i], "--limiter") == 0) { |  | 
|   349       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   350       ASSERT_EQ(apm->kNoError, |  | 
|   351                 apm->gain_control()->enable_limiter(true)); |  | 
|   352  |  | 
|   353     } else if (strcmp(argv[i], "--no_limiter") == 0) { |  | 
|   354       ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); |  | 
|   355       ASSERT_EQ(apm->kNoError, |  | 
|   356                 apm->gain_control()->enable_limiter(false)); |  | 
|   357  |  | 
|   358     } else if (strcmp(argv[i], "-hpf") == 0) { |  | 
|   359       ASSERT_EQ(apm->kNoError, apm->high_pass_filter()->Enable(true)); |  | 
|   360  |  | 
|   361     } else if (strcmp(argv[i], "-ns") == 0) { |  | 
|   362       ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); |  | 
|   363  |  | 
|   364     } else if (strcmp(argv[i], "--ns_low") == 0) { |  | 
|   365       ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); |  | 
|   366       ASSERT_EQ(apm->kNoError, |  | 
|   367           apm->noise_suppression()->set_level(NoiseSuppression::kLow)); |  | 
|   368  |  | 
|   369     } else if (strcmp(argv[i], "--ns_moderate") == 0) { |  | 
|   370       ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); |  | 
|   371       ASSERT_EQ(apm->kNoError, |  | 
|   372           apm->noise_suppression()->set_level(NoiseSuppression::kModerate)); |  | 
|   373  |  | 
|   374     } else if (strcmp(argv[i], "--ns_high") == 0) { |  | 
|   375       ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); |  | 
|   376       ASSERT_EQ(apm->kNoError, |  | 
|   377           apm->noise_suppression()->set_level(NoiseSuppression::kHigh)); |  | 
|   378  |  | 
|   379     } else if (strcmp(argv[i], "--ns_very_high") == 0) { |  | 
|   380       ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); |  | 
|   381       ASSERT_EQ(apm->kNoError, |  | 
|   382           apm->noise_suppression()->set_level(NoiseSuppression::kVeryHigh)); |  | 
|   383  |  | 
|   384     } else if (strcmp(argv[i], "--ns_prob_file") == 0) { |  | 
|   385       i++; |  | 
|   386       ASSERT_LT(i, argc) << "Specify filename after --ns_prob_file"; |  | 
|   387       ns_prob_filename = argv[i]; |  | 
|   388  |  | 
|   389     } else if (strcmp(argv[i], "-vad") == 0) { |  | 
|   390       ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); |  | 
|   391  |  | 
|   392     } else if (strcmp(argv[i], "--vad_very_low") == 0) { |  | 
|   393       ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); |  | 
|   394       ASSERT_EQ(apm->kNoError, |  | 
|   395           apm->voice_detection()->set_likelihood( |  | 
|   396               VoiceDetection::kVeryLowLikelihood)); |  | 
|   397  |  | 
|   398     } else if (strcmp(argv[i], "--vad_low") == 0) { |  | 
|   399       ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); |  | 
|   400       ASSERT_EQ(apm->kNoError, |  | 
|   401           apm->voice_detection()->set_likelihood( |  | 
|   402               VoiceDetection::kLowLikelihood)); |  | 
|   403  |  | 
|   404     } else if (strcmp(argv[i], "--vad_moderate") == 0) { |  | 
|   405       ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); |  | 
|   406       ASSERT_EQ(apm->kNoError, |  | 
|   407           apm->voice_detection()->set_likelihood( |  | 
|   408               VoiceDetection::kModerateLikelihood)); |  | 
|   409  |  | 
|   410     } else if (strcmp(argv[i], "--vad_high") == 0) { |  | 
|   411       ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); |  | 
|   412       ASSERT_EQ(apm->kNoError, |  | 
|   413           apm->voice_detection()->set_likelihood( |  | 
|   414               VoiceDetection::kHighLikelihood)); |  | 
|   415  |  | 
|   416     } else if (strcmp(argv[i], "--vad_out_file") == 0) { |  | 
|   417       i++; |  | 
|   418       ASSERT_LT(i, argc) << "Specify filename after --vad_out_file"; |  | 
|   419       vad_out_filename = argv[i]; |  | 
|   420  |  | 
|   421     } else if (strcmp(argv[i], "-expns") == 0) { |  | 
|   422       config.Set<ExperimentalNs>(new ExperimentalNs(true)); |  | 
|   423  |  | 
|   424     } else if (strcmp(argv[i], "--noasm") == 0) { |  | 
|   425       WebRtc_GetCPUInfo = WebRtc_GetCPUInfoNoASM; |  | 
|   426       // We need to reinitialize here if components have already been enabled. |  | 
|   427       ASSERT_EQ(apm->kNoError, apm->Initialize()); |  | 
|   428  |  | 
|   429     } else if (strcmp(argv[i], "--add_delay") == 0) { |  | 
|   430       i++; |  | 
|   431       ASSERT_EQ(1, sscanf(argv[i], "%d", &extra_delay_ms)); |  | 
|   432  |  | 
|   433     } else if (strcmp(argv[i], "--delay") == 0) { |  | 
|   434       i++; |  | 
|   435       ASSERT_EQ(1, sscanf(argv[i], "%d", &override_delay_ms)); |  | 
|   436  |  | 
|   437     } else if (strcmp(argv[i], "--perf") == 0) { |  | 
|   438       perf_testing = true; |  | 
|   439  |  | 
|   440     } else if (strcmp(argv[i], "--quiet") == 0) { |  | 
|   441       verbose = false; |  | 
|   442       progress = false; |  | 
|   443  |  | 
|   444     } else if (strcmp(argv[i], "--no_progress") == 0) { |  | 
|   445       progress = false; |  | 
|   446  |  | 
|   447     } else if (strcmp(argv[i], "--raw_output") == 0) { |  | 
|   448       raw_output = true; |  | 
|   449  |  | 
|   450     } else if (strcmp(argv[i], "--debug_file") == 0) { |  | 
|   451       i++; |  | 
|   452       ASSERT_LT(i, argc) << "Specify filename after --debug_file"; |  | 
|   453       ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i], -1)); |  | 
|   454     } else { |  | 
|   455       FAIL() << "Unrecognized argument " << argv[i]; |  | 
|   456     } |  | 
|   457   } |  | 
|   458   apm->ApplyConfig(apm_config); |  | 
|   459   apm->SetExtraOptions(config); |  | 
|   460  |  | 
|   461   // If we're reading a protobuf file, ensure a simulation hasn't also |  | 
|   462   // been requested (which makes no sense...) |  | 
|   463   ASSERT_FALSE(pb_filename && simulating); |  | 
|   464  |  | 
|   465   if (verbose) { |  | 
|   466     printf("Sample rate: %d Hz\n", sample_rate_hz); |  | 
|   467     printf("Primary channels: %" PRIuS " (in), %" PRIuS " (out)\n", |  | 
|   468            num_capture_input_channels, |  | 
|   469            num_capture_output_channels); |  | 
|   470     printf("Reverse channels: %" PRIuS "\n", num_render_channels); |  | 
|   471   } |  | 
|   472  |  | 
|   473   const std::string out_path = webrtc::test::OutputPath(); |  | 
|   474   const char far_file_default[] = "apm_far.pcm"; |  | 
|   475   const char near_file_default[] = "apm_near.pcm"; |  | 
|   476   const char event_filename[] = "apm_event.dat"; |  | 
|   477   const char delay_filename[] = "apm_delay.dat"; |  | 
|   478   const char drift_filename[] = "apm_drift.dat"; |  | 
|   479   const std::string vad_file_default = out_path + "vad_out.dat"; |  | 
|   480   const std::string ns_prob_file_default = out_path + "ns_prob.dat"; |  | 
|   481  |  | 
|   482   if (!simulating) { |  | 
|   483     far_filename = far_file_default; |  | 
|   484     near_filename = near_file_default; |  | 
|   485   } |  | 
|   486  |  | 
|   487   if (out_filename.size() == 0) { |  | 
|   488     out_filename = out_path + "out"; |  | 
|   489   } |  | 
|   490  |  | 
|   491   if (!vad_out_filename) { |  | 
|   492     vad_out_filename = vad_file_default.c_str(); |  | 
|   493   } |  | 
|   494  |  | 
|   495   if (!ns_prob_filename) { |  | 
|   496     ns_prob_filename = ns_prob_file_default.c_str(); |  | 
|   497   } |  | 
|   498  |  | 
|   499   FILE* pb_file = NULL; |  | 
|   500   FILE* far_file = NULL; |  | 
|   501   FILE* near_file = NULL; |  | 
|   502   FILE* event_file = NULL; |  | 
|   503   FILE* delay_file = NULL; |  | 
|   504   FILE* drift_file = NULL; |  | 
|   505   FILE* vad_out_file = NULL; |  | 
|   506   FILE* ns_prob_file = NULL; |  | 
|   507   FILE* aecm_echo_path_in_file = NULL; |  | 
|   508   FILE* aecm_echo_path_out_file = NULL; |  | 
|   509  |  | 
|   510   std::unique_ptr<WavWriter> output_wav_file; |  | 
|   511   std::unique_ptr<RawFile> output_raw_file; |  | 
|   512  |  | 
|   513   if (pb_filename) { |  | 
|   514     pb_file = OpenFile(pb_filename, "rb"); |  | 
|   515   } else { |  | 
|   516     if (far_filename) { |  | 
|   517       far_file = OpenFile(far_filename, "rb"); |  | 
|   518     } |  | 
|   519  |  | 
|   520     near_file = OpenFile(near_filename, "rb"); |  | 
|   521     if (!simulating) { |  | 
|   522       event_file = OpenFile(event_filename, "rb"); |  | 
|   523       delay_file = OpenFile(delay_filename, "rb"); |  | 
|   524       drift_file = OpenFile(drift_filename, "rb"); |  | 
|   525     } |  | 
|   526   } |  | 
|   527  |  | 
|   528   int near_size_bytes = 0; |  | 
|   529   if (pb_file) { |  | 
|   530     struct stat st; |  | 
|   531     stat(pb_filename, &st); |  | 
|   532     // Crude estimate, but should be good enough. |  | 
|   533     near_size_bytes = st.st_size / 3; |  | 
|   534   } else { |  | 
|   535     struct stat st; |  | 
|   536     stat(near_filename, &st); |  | 
|   537     near_size_bytes = st.st_size; |  | 
|   538   } |  | 
|   539  |  | 
|   540   if (apm->voice_detection()->is_enabled()) { |  | 
|   541     vad_out_file = OpenFile(vad_out_filename, "wb"); |  | 
|   542   } |  | 
|   543  |  | 
|   544   if (apm->noise_suppression()->is_enabled()) { |  | 
|   545     ns_prob_file = OpenFile(ns_prob_filename, "wb"); |  | 
|   546   } |  | 
|   547  |  | 
|   548   if (aecm_echo_path_in_filename != NULL) { |  | 
|   549     aecm_echo_path_in_file = OpenFile(aecm_echo_path_in_filename, "rb"); |  | 
|   550  |  | 
|   551     const size_t path_size = |  | 
|   552         apm->echo_control_mobile()->echo_path_size_bytes(); |  | 
|   553     std::unique_ptr<char[]> echo_path(new char[path_size]); |  | 
|   554     ASSERT_EQ(path_size, fread(echo_path.get(), |  | 
|   555                                sizeof(char), |  | 
|   556                                path_size, |  | 
|   557                                aecm_echo_path_in_file)); |  | 
|   558     EXPECT_EQ(apm->kNoError, |  | 
|   559               apm->echo_control_mobile()->SetEchoPath(echo_path.get(), |  | 
|   560                                                       path_size)); |  | 
|   561     fclose(aecm_echo_path_in_file); |  | 
|   562     aecm_echo_path_in_file = NULL; |  | 
|   563   } |  | 
|   564  |  | 
|   565   if (aecm_echo_path_out_filename != NULL) { |  | 
|   566     aecm_echo_path_out_file = OpenFile(aecm_echo_path_out_filename, "wb"); |  | 
|   567   } |  | 
|   568  |  | 
|   569   size_t read_count = 0; |  | 
|   570   int reverse_count = 0; |  | 
|   571   int primary_count = 0; |  | 
|   572   int near_read_bytes = 0; |  | 
|   573   int64_t acc_nanos = 0; |  | 
|   574  |  | 
|   575   AudioFrame far_frame; |  | 
|   576   AudioFrame near_frame; |  | 
|   577  |  | 
|   578   int delay_ms = 0; |  | 
|   579   int drift_samples = 0; |  | 
|   580   int capture_level = 127; |  | 
|   581   int8_t stream_has_voice = 0; |  | 
|   582   float ns_speech_prob = 0.0f; |  | 
|   583  |  | 
|   584   int64_t t0 = rtc::TimeNanos(); |  | 
|   585   int64_t t1 = t0; |  | 
|   586   int64_t max_time_us = 0; |  | 
|   587   int64_t max_time_reverse_us = 0; |  | 
|   588   int64_t min_time_us = 1e6; |  | 
|   589   int64_t min_time_reverse_us = 1e6; |  | 
|   590  |  | 
|   591   // TODO(ajm): Ideally we would refactor this block into separate functions, |  | 
|   592   //            but for now we want to share the variables. |  | 
|   593   if (pb_file) { |  | 
|   594     Event event_msg; |  | 
|   595     std::unique_ptr<ChannelBuffer<float> > reverse_cb; |  | 
|   596     std::unique_ptr<ChannelBuffer<float> > primary_cb; |  | 
|   597     int output_sample_rate = 32000; |  | 
|   598     AudioProcessing::ChannelLayout output_layout = AudioProcessing::kMono; |  | 
|   599     while (ReadMessageFromFile(pb_file, &event_msg)) { |  | 
|   600       std::ostringstream trace_stream; |  | 
|   601       trace_stream << "Processed frames: " << reverse_count << " (reverse), " |  | 
|   602                    << primary_count << " (primary)"; |  | 
|   603       SCOPED_TRACE(trace_stream.str()); |  | 
|   604  |  | 
|   605       if (event_msg.type() == Event::INIT) { |  | 
|   606         ASSERT_TRUE(event_msg.has_init()); |  | 
|   607         const Init msg = event_msg.init(); |  | 
|   608  |  | 
|   609         ASSERT_TRUE(msg.has_sample_rate()); |  | 
|   610         ASSERT_TRUE(msg.has_num_input_channels()); |  | 
|   611         ASSERT_TRUE(msg.has_num_output_channels()); |  | 
|   612         ASSERT_TRUE(msg.has_num_reverse_channels()); |  | 
|   613         int reverse_sample_rate = msg.sample_rate(); |  | 
|   614         if (msg.has_reverse_sample_rate()) { |  | 
|   615           reverse_sample_rate = msg.reverse_sample_rate(); |  | 
|   616         } |  | 
|   617         output_sample_rate = msg.sample_rate(); |  | 
|   618         if (msg.has_output_sample_rate()) { |  | 
|   619           output_sample_rate = msg.output_sample_rate(); |  | 
|   620         } |  | 
|   621         output_layout = |  | 
|   622             LayoutFromChannels(static_cast<size_t>(msg.num_output_channels())); |  | 
|   623         ASSERT_EQ(kNoErr, |  | 
|   624                   apm->Initialize( |  | 
|   625                       msg.sample_rate(), |  | 
|   626                       output_sample_rate, |  | 
|   627                       reverse_sample_rate, |  | 
|   628                       LayoutFromChannels( |  | 
|   629                           static_cast<size_t>(msg.num_input_channels())), |  | 
|   630                       output_layout, |  | 
|   631                       LayoutFromChannels( |  | 
|   632                           static_cast<size_t>(msg.num_reverse_channels())))); |  | 
|   633  |  | 
|   634         samples_per_channel = msg.sample_rate() / 100; |  | 
|   635         far_frame.sample_rate_hz_ = reverse_sample_rate; |  | 
|   636         far_frame.samples_per_channel_ = reverse_sample_rate / 100; |  | 
|   637         far_frame.num_channels_ = msg.num_reverse_channels(); |  | 
|   638         near_frame.sample_rate_hz_ = msg.sample_rate(); |  | 
|   639         near_frame.samples_per_channel_ = samples_per_channel; |  | 
|   640         near_frame.num_channels_ = msg.num_input_channels(); |  | 
|   641         reverse_cb.reset(new ChannelBuffer<float>( |  | 
|   642             far_frame.samples_per_channel_, |  | 
|   643             msg.num_reverse_channels())); |  | 
|   644         primary_cb.reset(new ChannelBuffer<float>(samples_per_channel, |  | 
|   645                                                   msg.num_input_channels())); |  | 
|   646  |  | 
|   647         if (verbose) { |  | 
|   648           printf("Init at frame: %d (primary), %d (reverse)\n", |  | 
|   649               primary_count, reverse_count); |  | 
|   650           printf("  Primary rates: %d Hz (in), %d Hz (out)\n", |  | 
|   651                  msg.sample_rate(), output_sample_rate); |  | 
|   652           printf("  Primary channels: %d (in), %d (out)\n", |  | 
|   653                  msg.num_input_channels(), |  | 
|   654                  msg.num_output_channels()); |  | 
|   655           printf("  Reverse rate: %d\n", reverse_sample_rate); |  | 
|   656           printf("  Reverse channels: %d\n", msg.num_reverse_channels()); |  | 
|   657         } |  | 
|   658  |  | 
|   659         if (!raw_output) { |  | 
|   660           // The WAV file needs to be reset every time, because it can't change |  | 
|   661           // its sample rate or number of channels. |  | 
|   662           output_wav_file.reset(new WavWriter( |  | 
|   663               out_filename + ".wav", output_sample_rate, |  | 
|   664               static_cast<size_t>(msg.num_output_channels()))); |  | 
|   665         } |  | 
|   666  |  | 
|   667       } else if (event_msg.type() == Event::REVERSE_STREAM) { |  | 
|   668         ASSERT_TRUE(event_msg.has_reverse_stream()); |  | 
|   669         ReverseStream msg = event_msg.reverse_stream(); |  | 
|   670         reverse_count++; |  | 
|   671  |  | 
|   672         ASSERT_TRUE(msg.has_data() ^ (msg.channel_size() > 0)); |  | 
|   673         if (msg.has_data()) { |  | 
|   674           ASSERT_EQ(sizeof(int16_t) * far_frame.samples_per_channel_ * |  | 
|   675               far_frame.num_channels_, msg.data().size()); |  | 
|   676           memcpy(far_frame.data_, msg.data().data(), msg.data().size()); |  | 
|   677         } else { |  | 
|   678           for (int i = 0; i < msg.channel_size(); ++i) { |  | 
|   679             memcpy(reverse_cb->channels()[i], |  | 
|   680                    msg.channel(i).data(), |  | 
|   681                    reverse_cb->num_frames() * |  | 
|   682                        sizeof(reverse_cb->channels()[i][0])); |  | 
|   683           } |  | 
|   684         } |  | 
|   685  |  | 
|   686         if (perf_testing) { |  | 
|   687           t0 = rtc::TimeNanos(); |  | 
|   688         } |  | 
|   689  |  | 
|   690         if (msg.has_data()) { |  | 
|   691           ASSERT_EQ(apm->kNoError, |  | 
|   692                     apm->ProcessReverseStream(&far_frame)); |  | 
|   693         } else { |  | 
|   694           ASSERT_EQ(apm->kNoError, |  | 
|   695                     apm->AnalyzeReverseStream( |  | 
|   696                         reverse_cb->channels(), |  | 
|   697                         far_frame.samples_per_channel_, |  | 
|   698                         far_frame.sample_rate_hz_, |  | 
|   699                         LayoutFromChannels(far_frame.num_channels_))); |  | 
|   700         } |  | 
|   701  |  | 
|   702         if (perf_testing) { |  | 
|   703           t1 = rtc::TimeNanos(); |  | 
|   704           int64_t diff_nanos = t1 - t0; |  | 
|   705           acc_nanos += diff_nanos; |  | 
|   706           int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec; |  | 
|   707           if (diff_us > max_time_reverse_us) { |  | 
|   708             max_time_reverse_us = diff_us; |  | 
|   709           } |  | 
|   710           if (diff_us < min_time_reverse_us) { |  | 
|   711             min_time_reverse_us = diff_us; |  | 
|   712           } |  | 
|   713         } |  | 
|   714  |  | 
|   715       } else if (event_msg.type() == Event::STREAM) { |  | 
|   716         ASSERT_TRUE(event_msg.has_stream()); |  | 
|   717         const Stream msg = event_msg.stream(); |  | 
|   718         primary_count++; |  | 
|   719  |  | 
|   720         ASSERT_TRUE(msg.has_input_data() ^ (msg.input_channel_size() > 0)); |  | 
|   721         if (msg.has_input_data()) { |  | 
|   722           ASSERT_EQ(sizeof(int16_t) * samples_per_channel * |  | 
|   723               near_frame.num_channels_, msg.input_data().size()); |  | 
|   724           memcpy(near_frame.data_, |  | 
|   725                  msg.input_data().data(), |  | 
|   726                  msg.input_data().size()); |  | 
|   727           near_read_bytes += msg.input_data().size(); |  | 
|   728         } else { |  | 
|   729           for (int i = 0; i < msg.input_channel_size(); ++i) { |  | 
|   730             memcpy(primary_cb->channels()[i], |  | 
|   731                    msg.input_channel(i).data(), |  | 
|   732                    primary_cb->num_frames() * |  | 
|   733                        sizeof(primary_cb->channels()[i][0])); |  | 
|   734             near_read_bytes += msg.input_channel(i).size(); |  | 
|   735           } |  | 
|   736         } |  | 
|   737  |  | 
|   738         if (progress && primary_count % 100 == 0) { |  | 
|   739           near_read_bytes = std::min(near_read_bytes, near_size_bytes); |  | 
|   740           printf("%.0f%% complete\r", |  | 
|   741               (near_read_bytes * 100.0) / near_size_bytes); |  | 
|   742           fflush(stdout); |  | 
|   743         } |  | 
|   744  |  | 
|   745         if (perf_testing) { |  | 
|   746           t0 = rtc::TimeNanos(); |  | 
|   747         } |  | 
|   748  |  | 
|   749         ASSERT_EQ(apm->kNoError, |  | 
|   750                   apm->gain_control()->set_stream_analog_level(msg.level())); |  | 
|   751         delay_ms = msg.delay() + extra_delay_ms; |  | 
|   752         if (override_delay_ms) { |  | 
|   753           delay_ms = override_delay_ms; |  | 
|   754         } |  | 
|   755         ASSERT_EQ(apm->kNoError, |  | 
|   756                   apm->set_stream_delay_ms(delay_ms)); |  | 
|   757         apm->echo_cancellation()->set_stream_drift_samples(msg.drift()); |  | 
|   758  |  | 
|   759         if (msg.has_keypress()) { |  | 
|   760           apm->set_stream_key_pressed(msg.keypress()); |  | 
|   761         } else { |  | 
|   762           apm->set_stream_key_pressed(true); |  | 
|   763         } |  | 
|   764  |  | 
|   765         int err = apm->kNoError; |  | 
|   766         if (msg.has_input_data()) { |  | 
|   767           err = apm->ProcessStream(&near_frame); |  | 
|   768           ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels()); |  | 
|   769         } else { |  | 
|   770           err = apm->ProcessStream( |  | 
|   771               primary_cb->channels(), |  | 
|   772               near_frame.samples_per_channel_, |  | 
|   773               near_frame.sample_rate_hz_, |  | 
|   774               LayoutFromChannels(near_frame.num_channels_), |  | 
|   775               output_sample_rate, |  | 
|   776               output_layout, |  | 
|   777               primary_cb->channels()); |  | 
|   778         } |  | 
|   779  |  | 
|   780         if (err == apm->kBadStreamParameterWarning) { |  | 
|   781           printf("Bad parameter warning. %s\n", trace_stream.str().c_str()); |  | 
|   782         } |  | 
|   783         ASSERT_TRUE(err == apm->kNoError || |  | 
|   784                     err == apm->kBadStreamParameterWarning); |  | 
|   785  |  | 
|   786         stream_has_voice = |  | 
|   787             static_cast<int8_t>(apm->voice_detection()->stream_has_voice()); |  | 
|   788         if (vad_out_file != NULL) { |  | 
|   789           ASSERT_EQ(1u, fwrite(&stream_has_voice, |  | 
|   790                                sizeof(stream_has_voice), |  | 
|   791                                1, |  | 
|   792                                vad_out_file)); |  | 
|   793         } |  | 
|   794  |  | 
|   795         if (ns_prob_file != NULL) { |  | 
|   796           ns_speech_prob = apm->noise_suppression()->speech_probability(); |  | 
|   797           ASSERT_EQ(1u, fwrite(&ns_speech_prob, |  | 
|   798                                sizeof(ns_speech_prob), |  | 
|   799                                1, |  | 
|   800                                ns_prob_file)); |  | 
|   801         } |  | 
|   802  |  | 
|   803         if (perf_testing) { |  | 
|   804           t1 = rtc::TimeNanos(); |  | 
|   805           int64_t diff_nanos = t1 - t0; |  | 
|   806           acc_nanos += diff_nanos; |  | 
|   807           int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec; |  | 
|   808           if (diff_us > max_time_us) { |  | 
|   809             max_time_us = diff_us; |  | 
|   810           } |  | 
|   811           if (diff_us < min_time_us) { |  | 
|   812             min_time_us = diff_us; |  | 
|   813           } |  | 
|   814         } |  | 
|   815  |  | 
|   816         const size_t samples_per_channel = output_sample_rate / 100; |  | 
|   817         if (msg.has_input_data()) { |  | 
|   818           if (raw_output && !output_raw_file) { |  | 
|   819             output_raw_file.reset(new RawFile(out_filename + ".pcm")); |  | 
|   820           } |  | 
|   821           WriteIntData(near_frame.data_, |  | 
|   822                        apm->num_output_channels() * samples_per_channel, |  | 
|   823                        output_wav_file.get(), |  | 
|   824                        output_raw_file.get()); |  | 
|   825         } else { |  | 
|   826           if (raw_output && !output_raw_file) { |  | 
|   827             output_raw_file.reset(new RawFile(out_filename + ".float")); |  | 
|   828           } |  | 
|   829           WriteFloatData(primary_cb->channels(), |  | 
|   830                          samples_per_channel, |  | 
|   831                          apm->num_output_channels(), |  | 
|   832                          output_wav_file.get(), |  | 
|   833                          output_raw_file.get()); |  | 
|   834         } |  | 
|   835       } |  | 
|   836     } |  | 
|   837  |  | 
|   838     ASSERT_TRUE(feof(pb_file)); |  | 
|   839  |  | 
|   840   } else { |  | 
|   841     enum Events { |  | 
|   842       kInitializeEvent, |  | 
|   843       kRenderEvent, |  | 
|   844       kCaptureEvent, |  | 
|   845       kResetEventDeprecated |  | 
|   846     }; |  | 
|   847     int16_t event = 0; |  | 
|   848     while (simulating || feof(event_file) == 0) { |  | 
|   849       std::ostringstream trace_stream; |  | 
|   850       trace_stream << "Processed frames: " << reverse_count << " (reverse), " |  | 
|   851                    << primary_count << " (primary)"; |  | 
|   852       SCOPED_TRACE(trace_stream.str()); |  | 
|   853  |  | 
|   854       if (simulating) { |  | 
|   855         if (far_file == NULL) { |  | 
|   856           event = kCaptureEvent; |  | 
|   857         } else { |  | 
|   858           event = (event == kCaptureEvent) ? kRenderEvent : kCaptureEvent; |  | 
|   859         } |  | 
|   860       } else { |  | 
|   861         read_count = fread(&event, sizeof(event), 1, event_file); |  | 
|   862         if (read_count != 1) { |  | 
|   863           break; |  | 
|   864         } |  | 
|   865       } |  | 
|   866  |  | 
|   867       far_frame.sample_rate_hz_ = sample_rate_hz; |  | 
|   868       far_frame.samples_per_channel_ = samples_per_channel; |  | 
|   869       far_frame.num_channels_ = num_render_channels; |  | 
|   870       near_frame.sample_rate_hz_ = sample_rate_hz; |  | 
|   871       near_frame.samples_per_channel_ = samples_per_channel; |  | 
|   872  |  | 
|   873       if (event == kInitializeEvent || event == kResetEventDeprecated) { |  | 
|   874         ASSERT_EQ(1u, |  | 
|   875             fread(&sample_rate_hz, sizeof(sample_rate_hz), 1, event_file)); |  | 
|   876         samples_per_channel = sample_rate_hz / 100; |  | 
|   877  |  | 
|   878         int32_t unused_device_sample_rate_hz; |  | 
|   879         ASSERT_EQ(1u, |  | 
|   880             fread(&unused_device_sample_rate_hz, |  | 
|   881                   sizeof(unused_device_sample_rate_hz), |  | 
|   882                   1, |  | 
|   883                   event_file)); |  | 
|   884  |  | 
|   885         ASSERT_EQ(kNoErr, apm->Initialize( |  | 
|   886                               sample_rate_hz, |  | 
|   887                               sample_rate_hz, |  | 
|   888                               sample_rate_hz, |  | 
|   889                               LayoutFromChannels(num_capture_input_channels), |  | 
|   890                               LayoutFromChannels(num_capture_output_channels), |  | 
|   891                               LayoutFromChannels(num_render_channels))); |  | 
|   892  |  | 
|   893         far_frame.sample_rate_hz_ = sample_rate_hz; |  | 
|   894         far_frame.samples_per_channel_ = samples_per_channel; |  | 
|   895         far_frame.num_channels_ = num_render_channels; |  | 
|   896         near_frame.sample_rate_hz_ = sample_rate_hz; |  | 
|   897         near_frame.samples_per_channel_ = samples_per_channel; |  | 
|   898  |  | 
|   899         if (!raw_output) { |  | 
|   900           // The WAV file needs to be reset every time, because it can't change |  | 
|   901           // it's sample rate or number of channels. |  | 
|   902           output_wav_file.reset(new WavWriter(out_filename + ".wav", |  | 
|   903                                               sample_rate_hz, |  | 
|   904                                               num_capture_output_channels)); |  | 
|   905         } |  | 
|   906  |  | 
|   907         if (verbose) { |  | 
|   908           printf("Init at frame: %d (primary), %d (reverse)\n", |  | 
|   909               primary_count, reverse_count); |  | 
|   910           printf("  Sample rate: %d Hz\n", sample_rate_hz); |  | 
|   911         } |  | 
|   912  |  | 
|   913       } else if (event == kRenderEvent) { |  | 
|   914         reverse_count++; |  | 
|   915  |  | 
|   916         size_t size = samples_per_channel * num_render_channels; |  | 
|   917         read_count = fread(far_frame.data_, |  | 
|   918                            sizeof(int16_t), |  | 
|   919                            size, |  | 
|   920                            far_file); |  | 
|   921  |  | 
|   922         if (simulating) { |  | 
|   923           if (read_count != size) { |  | 
|   924             // Read an equal amount from the near file to avoid errors due to |  | 
|   925             // not reaching end-of-file. |  | 
|   926             EXPECT_EQ(0, fseek(near_file, read_count * sizeof(int16_t), |  | 
|   927                       SEEK_CUR)); |  | 
|   928             break;  // This is expected. |  | 
|   929           } |  | 
|   930         } else { |  | 
|   931           ASSERT_EQ(size, read_count); |  | 
|   932         } |  | 
|   933  |  | 
|   934         if (perf_testing) { |  | 
|   935           t0 = rtc::TimeNanos(); |  | 
|   936         } |  | 
|   937  |  | 
|   938         ASSERT_EQ(apm->kNoError, |  | 
|   939                   apm->ProcessReverseStream(&far_frame)); |  | 
|   940  |  | 
|   941         if (perf_testing) { |  | 
|   942           t1 = rtc::TimeNanos(); |  | 
|   943           int64_t diff_nanos = t1 - t0; |  | 
|   944           acc_nanos += diff_nanos; |  | 
|   945           int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec; |  | 
|   946           if (diff_us > max_time_reverse_us) { |  | 
|   947             max_time_reverse_us = diff_us; |  | 
|   948           } |  | 
|   949           if (diff_us < min_time_reverse_us) { |  | 
|   950             min_time_reverse_us = diff_us; |  | 
|   951           } |  | 
|   952         } |  | 
|   953  |  | 
|   954       } else if (event == kCaptureEvent) { |  | 
|   955         primary_count++; |  | 
|   956         near_frame.num_channels_ = num_capture_input_channels; |  | 
|   957  |  | 
|   958         size_t size = samples_per_channel * num_capture_input_channels; |  | 
|   959         read_count = fread(near_frame.data_, |  | 
|   960                            sizeof(int16_t), |  | 
|   961                            size, |  | 
|   962                            near_file); |  | 
|   963  |  | 
|   964         near_read_bytes += read_count * sizeof(int16_t); |  | 
|   965         if (progress && primary_count % 100 == 0) { |  | 
|   966           printf("%.0f%% complete\r", |  | 
|   967               (near_read_bytes * 100.0) / near_size_bytes); |  | 
|   968           fflush(stdout); |  | 
|   969         } |  | 
|   970         if (simulating) { |  | 
|   971           if (read_count != size) { |  | 
|   972             break;  // This is expected. |  | 
|   973           } |  | 
|   974  |  | 
|   975           delay_ms = 0; |  | 
|   976           drift_samples = 0; |  | 
|   977         } else { |  | 
|   978           ASSERT_EQ(size, read_count); |  | 
|   979  |  | 
|   980           // TODO(ajm): sizeof(delay_ms) for current files? |  | 
|   981           ASSERT_EQ(1u, |  | 
|   982               fread(&delay_ms, 2, 1, delay_file)); |  | 
|   983           ASSERT_EQ(1u, |  | 
|   984               fread(&drift_samples, sizeof(drift_samples), 1, drift_file)); |  | 
|   985         } |  | 
|   986  |  | 
|   987         if (apm->gain_control()->is_enabled() && |  | 
|   988             apm->gain_control()->mode() == GainControl::kAdaptiveAnalog) { |  | 
|   989           SimulateMic(capture_level, &near_frame); |  | 
|   990         } |  | 
|   991  |  | 
|   992         if (perf_testing) { |  | 
|   993           t0 = rtc::TimeNanos(); |  | 
|   994         } |  | 
|   995  |  | 
|   996         const int capture_level_in = capture_level; |  | 
|   997         ASSERT_EQ(apm->kNoError, |  | 
|   998                   apm->gain_control()->set_stream_analog_level(capture_level)); |  | 
|   999         delay_ms += extra_delay_ms; |  | 
|  1000         if (override_delay_ms) { |  | 
|  1001           delay_ms = override_delay_ms; |  | 
|  1002         } |  | 
|  1003         ASSERT_EQ(apm->kNoError, |  | 
|  1004                   apm->set_stream_delay_ms(delay_ms)); |  | 
|  1005         apm->echo_cancellation()->set_stream_drift_samples(drift_samples); |  | 
|  1006  |  | 
|  1007         apm->set_stream_key_pressed(true); |  | 
|  1008  |  | 
|  1009         int err = apm->ProcessStream(&near_frame); |  | 
|  1010         if (err == apm->kBadStreamParameterWarning) { |  | 
|  1011           printf("Bad parameter warning. %s\n", trace_stream.str().c_str()); |  | 
|  1012         } |  | 
|  1013         ASSERT_TRUE(err == apm->kNoError || |  | 
|  1014                     err == apm->kBadStreamParameterWarning); |  | 
|  1015         ASSERT_TRUE(near_frame.num_channels_ == apm->num_output_channels()); |  | 
|  1016  |  | 
|  1017         capture_level = apm->gain_control()->stream_analog_level(); |  | 
|  1018  |  | 
|  1019         stream_has_voice = |  | 
|  1020             static_cast<int8_t>(apm->voice_detection()->stream_has_voice()); |  | 
|  1021         if (vad_out_file != NULL) { |  | 
|  1022           ASSERT_EQ(1u, fwrite(&stream_has_voice, |  | 
|  1023                                sizeof(stream_has_voice), |  | 
|  1024                                1, |  | 
|  1025                                vad_out_file)); |  | 
|  1026         } |  | 
|  1027  |  | 
|  1028         if (ns_prob_file != NULL) { |  | 
|  1029           ns_speech_prob = apm->noise_suppression()->speech_probability(); |  | 
|  1030           ASSERT_EQ(1u, fwrite(&ns_speech_prob, |  | 
|  1031                                sizeof(ns_speech_prob), |  | 
|  1032                                1, |  | 
|  1033                                ns_prob_file)); |  | 
|  1034         } |  | 
|  1035  |  | 
|  1036         if (apm->gain_control()->mode() != GainControl::kAdaptiveAnalog) { |  | 
|  1037           ASSERT_EQ(capture_level_in, capture_level); |  | 
|  1038         } |  | 
|  1039  |  | 
|  1040         if (perf_testing) { |  | 
|  1041           t1 = rtc::TimeNanos(); |  | 
|  1042           int64_t diff_nanos = t1 - t0; |  | 
|  1043           acc_nanos += diff_nanos; |  | 
|  1044           int64_t diff_us = diff_nanos / rtc::kNumNanosecsPerMicrosec; |  | 
|  1045           if (diff_us > max_time_us) { |  | 
|  1046             max_time_us = diff_us; |  | 
|  1047           } |  | 
|  1048           if (diff_us < min_time_us) { |  | 
|  1049             min_time_us = diff_us; |  | 
|  1050           } |  | 
|  1051         } |  | 
|  1052  |  | 
|  1053         if (raw_output && !output_raw_file) { |  | 
|  1054           output_raw_file.reset(new RawFile(out_filename + ".pcm")); |  | 
|  1055         } |  | 
|  1056         if (!raw_output && !output_wav_file) { |  | 
|  1057           output_wav_file.reset(new WavWriter(out_filename + ".wav", |  | 
|  1058                                               sample_rate_hz, |  | 
|  1059                                               num_capture_output_channels)); |  | 
|  1060         } |  | 
|  1061         WriteIntData(near_frame.data_, |  | 
|  1062                      size, |  | 
|  1063                      output_wav_file.get(), |  | 
|  1064                      output_raw_file.get()); |  | 
|  1065       } else { |  | 
|  1066         FAIL() << "Event " << event << " is unrecognized"; |  | 
|  1067       } |  | 
|  1068     } |  | 
|  1069   } |  | 
|  1070   if (progress) { |  | 
|  1071     printf("100%% complete\r"); |  | 
|  1072   } |  | 
|  1073  |  | 
|  1074   if (aecm_echo_path_out_file != NULL) { |  | 
|  1075     const size_t path_size = |  | 
|  1076         apm->echo_control_mobile()->echo_path_size_bytes(); |  | 
|  1077     std::unique_ptr<char[]> echo_path(new char[path_size]); |  | 
|  1078     apm->echo_control_mobile()->GetEchoPath(echo_path.get(), path_size); |  | 
|  1079     ASSERT_EQ(path_size, fwrite(echo_path.get(), |  | 
|  1080                                 sizeof(char), |  | 
|  1081                                 path_size, |  | 
|  1082                                 aecm_echo_path_out_file)); |  | 
|  1083     fclose(aecm_echo_path_out_file); |  | 
|  1084     aecm_echo_path_out_file = NULL; |  | 
|  1085   } |  | 
|  1086  |  | 
|  1087   if (verbose) { |  | 
|  1088     printf("\nProcessed frames: %d (primary), %d (reverse)\n", |  | 
|  1089         primary_count, reverse_count); |  | 
|  1090  |  | 
|  1091     if (apm->level_estimator()->is_enabled()) { |  | 
|  1092       printf("\n--Level metrics--\n"); |  | 
|  1093       printf("RMS: %d dBFS\n", -apm->level_estimator()->RMS()); |  | 
|  1094     } |  | 
|  1095     if (apm->echo_cancellation()->are_metrics_enabled()) { |  | 
|  1096       EchoCancellation::Metrics metrics; |  | 
|  1097       apm->echo_cancellation()->GetMetrics(&metrics); |  | 
|  1098       printf("\n--Echo metrics--\n"); |  | 
|  1099       printf("(avg, max, min)\n"); |  | 
|  1100       printf("ERL:  "); |  | 
|  1101       PrintStat(metrics.echo_return_loss); |  | 
|  1102       printf("ERLE: "); |  | 
|  1103       PrintStat(metrics.echo_return_loss_enhancement); |  | 
|  1104       printf("ANLP: "); |  | 
|  1105       PrintStat(metrics.a_nlp); |  | 
|  1106     } |  | 
|  1107     if (apm->echo_cancellation()->is_delay_logging_enabled()) { |  | 
|  1108       int median = 0; |  | 
|  1109       int std = 0; |  | 
|  1110       float fraction_poor_delays = 0; |  | 
|  1111       apm->echo_cancellation()->GetDelayMetrics(&median, &std, |  | 
|  1112                                                 &fraction_poor_delays); |  | 
|  1113       printf("\n--Delay metrics--\n"); |  | 
|  1114       printf("Median:             %3d\n", median); |  | 
|  1115       printf("Standard deviation: %3d\n", std); |  | 
|  1116       printf("Poor delay values:  %3.1f%%\n", fraction_poor_delays * 100); |  | 
|  1117     } |  | 
|  1118   } |  | 
|  1119  |  | 
|  1120   if (!pb_file) { |  | 
|  1121     int8_t temp_int8; |  | 
|  1122     if (far_file) { |  | 
|  1123       read_count = fread(&temp_int8, sizeof(temp_int8), 1, far_file); |  | 
|  1124       EXPECT_NE(0, feof(far_file)) << "Far-end file not fully processed"; |  | 
|  1125     } |  | 
|  1126  |  | 
|  1127     read_count = fread(&temp_int8, sizeof(temp_int8), 1, near_file); |  | 
|  1128     EXPECT_NE(0, feof(near_file)) << "Near-end file not fully processed"; |  | 
|  1129  |  | 
|  1130     if (!simulating) { |  | 
|  1131       read_count = fread(&temp_int8, sizeof(temp_int8), 1, event_file); |  | 
|  1132       EXPECT_NE(0, feof(event_file)) << "Event file not fully processed"; |  | 
|  1133       read_count = fread(&temp_int8, sizeof(temp_int8), 1, delay_file); |  | 
|  1134       EXPECT_NE(0, feof(delay_file)) << "Delay file not fully processed"; |  | 
|  1135       read_count = fread(&temp_int8, sizeof(temp_int8), 1, drift_file); |  | 
|  1136       EXPECT_NE(0, feof(drift_file)) << "Drift file not fully processed"; |  | 
|  1137     } |  | 
|  1138   } |  | 
|  1139  |  | 
|  1140   if (perf_testing) { |  | 
|  1141     if (primary_count > 0) { |  | 
|  1142       int64_t exec_time = acc_nanos / rtc::kNumNanosecsPerMillisec; |  | 
|  1143       printf("\nTotal time: %.3f s, file time: %.2f s\n", |  | 
|  1144         exec_time * 0.001, primary_count * 0.01); |  | 
|  1145       printf("Time per frame: %.3f ms (average), %.3f ms (max)," |  | 
|  1146              " %.3f ms (min)\n", |  | 
|  1147           (exec_time * 1.0) / primary_count, |  | 
|  1148           (max_time_us + max_time_reverse_us) / 1000.0, |  | 
|  1149           (min_time_us + min_time_reverse_us) / 1000.0); |  | 
|  1150       // Record the results with Perf test tools. |  | 
|  1151       webrtc::test::PrintResult("audioproc", "", "time_per_10ms_frame", |  | 
|  1152           (exec_time * 1000) / primary_count, "us", false); |  | 
|  1153     } else { |  | 
|  1154       printf("Warning: no capture frames\n"); |  | 
|  1155     } |  | 
|  1156   } |  | 
|  1157 } |  | 
|  1158  |  | 
|  1159 }  // namespace |  | 
|  1160 }  // namespace webrtc |  | 
|  1161  |  | 
|  1162 int main(int argc, char* argv[]) { |  | 
|  1163   webrtc::void_main(argc, argv); |  | 
|  1164  |  | 
|  1165   // Optional, but removes memory leak noise from Valgrind. |  | 
|  1166   google::protobuf::ShutdownProtobufLibrary(); |  | 
|  1167   return 0; |  | 
|  1168 } |  | 
| OLD | NEW |