1/* 2 * Copyright (c) 2014 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 <stdio.h> 12#include <iostream> 13#include <sstream> 14#include <string> 15#include <utility> 16 17#include "gflags/gflags.h" 18#include "webrtc/base/checks.h" 19#include "webrtc/base/format_macros.h" 20#include "webrtc/base/scoped_ptr.h" 21#include "webrtc/common_audio/channel_buffer.h" 22#include "webrtc/common_audio/wav_file.h" 23#include "webrtc/modules/audio_processing/include/audio_processing.h" 24#include "webrtc/modules/audio_processing/test/audio_file_processor.h" 25#include "webrtc/modules/audio_processing/test/protobuf_utils.h" 26#include "webrtc/modules/audio_processing/test/test_utils.h" 27#include "webrtc/system_wrappers/include/tick_util.h" 28#include "webrtc/test/testsupport/trace_to_stderr.h" 29 30namespace { 31 32bool ValidateOutChannels(const char* flagname, int32_t value) { 33 return value >= 0; 34} 35 36} // namespace 37 38DEFINE_string(dump, "", "Name of the aecdump debug file to read from."); 39DEFINE_string(i, "", "Name of the capture input stream file to read from."); 40DEFINE_string( 41 o, 42 "out.wav", 43 "Name of the output file to write the processed capture stream to."); 44DEFINE_int32(out_channels, 1, "Number of output channels."); 45const bool out_channels_dummy = 46 google::RegisterFlagValidator(&FLAGS_out_channels, &ValidateOutChannels); 47DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz."); 48DEFINE_string(mic_positions, "", 49 "Space delimited cartesian coordinates of microphones in meters. " 50 "The coordinates of each point are contiguous. " 51 "For a two element array: \"x1 y1 z1 x2 y2 z2\""); 52DEFINE_double( 53 target_angle_degrees, 54 90, 55 "The azimuth of the target in degrees. Only applies to beamforming."); 56 57DEFINE_bool(aec, false, "Enable echo cancellation."); 58DEFINE_bool(agc, false, "Enable automatic gain control."); 59DEFINE_bool(hpf, false, "Enable high-pass filtering."); 60DEFINE_bool(ns, false, "Enable noise suppression."); 61DEFINE_bool(ts, false, "Enable transient suppression."); 62DEFINE_bool(bf, false, "Enable beamforming."); 63DEFINE_bool(ie, false, "Enable intelligibility enhancer."); 64DEFINE_bool(all, false, "Enable all components."); 65 66DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3]."); 67 68DEFINE_bool(perf, false, "Enable performance tests."); 69 70namespace webrtc { 71namespace { 72 73const int kChunksPerSecond = 100; 74const char kUsage[] = 75 "Command-line tool to run audio processing on WAV files. Accepts either\n" 76 "an input capture WAV file or protobuf debug dump and writes to an output\n" 77 "WAV file.\n" 78 "\n" 79 "All components are disabled by default. If any bi-directional components\n" 80 "are enabled, only debug dump files are permitted."; 81 82} // namespace 83 84int main(int argc, char* argv[]) { 85 google::SetUsageMessage(kUsage); 86 google::ParseCommandLineFlags(&argc, &argv, true); 87 88 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) { 89 fprintf(stderr, 90 "An input file must be specified with either -i or -dump.\n"); 91 return 1; 92 } 93 if (FLAGS_dump.empty() && (FLAGS_aec || FLAGS_ie)) { 94 fprintf(stderr, "-aec and -ie require a -dump file.\n"); 95 return 1; 96 } 97 if (FLAGS_ie) { 98 fprintf(stderr, 99 "FIXME(ajm): The intelligibility enhancer output is not dumped.\n"); 100 return 1; 101 } 102 103 test::TraceToStderr trace_to_stderr(true); 104 Config config; 105 if (FLAGS_bf || FLAGS_all) { 106 if (FLAGS_mic_positions.empty()) { 107 fprintf(stderr, "-mic_positions must be specified when -bf is used.\n"); 108 return 1; 109 } 110 config.Set<Beamforming>(new Beamforming( 111 true, ParseArrayGeometry(FLAGS_mic_positions), 112 SphericalPointf(DegreesToRadians(FLAGS_target_angle_degrees), 0.f, 113 1.f))); 114 } 115 config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all)); 116 config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all)); 117 118 rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config)); 119 RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all)); 120 RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all)); 121 RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all)); 122 RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all)); 123 if (FLAGS_ns_level != -1) { 124 RTC_CHECK_EQ(kNoErr, 125 ap->noise_suppression()->set_level( 126 static_cast<NoiseSuppression::Level>(FLAGS_ns_level))); 127 } 128 ap->set_stream_key_pressed(FLAGS_ts); 129 130 rtc::scoped_ptr<AudioFileProcessor> processor; 131 auto out_file = rtc_make_scoped_ptr(new WavWriter( 132 FLAGS_o, FLAGS_out_sample_rate, static_cast<size_t>(FLAGS_out_channels))); 133 std::cout << FLAGS_o << ": " << out_file->FormatAsString() << std::endl; 134 if (FLAGS_dump.empty()) { 135 auto in_file = rtc_make_scoped_ptr(new WavReader(FLAGS_i)); 136 std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl; 137 processor.reset(new WavFileProcessor(std::move(ap), std::move(in_file), 138 std::move(out_file))); 139 140 } else { 141 processor.reset(new AecDumpFileProcessor( 142 std::move(ap), fopen(FLAGS_dump.c_str(), "rb"), std::move(out_file))); 143 } 144 145 int num_chunks = 0; 146 while (processor->ProcessChunk()) { 147 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond); 148 ++num_chunks; 149 } 150 151 if (FLAGS_perf) { 152 const auto& proc_time = processor->proc_time(); 153 int64_t exec_time_us = proc_time.sum.Microseconds(); 154 printf( 155 "\nExecution time: %.3f s, File time: %.2f s\n" 156 "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n", 157 exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond, 158 exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(), 159 1.f * proc_time.min.Microseconds()); 160 } 161 162 return 0; 163} 164 165} // namespace webrtc 166 167int main(int argc, char* argv[]) { 168 return webrtc::main(argc, argv); 169} 170