1 /* 2 * Copyright (c) 2011 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 // Commandline tool to unpack audioproc debug files. 12 // 13 // The debug files are dumped as protobuf blobs. For analysis, it's necessary 14 // to unpack the file into its component parts: audio and other data. 15 16 #include <stdio.h> 17 18 #include "gflags/gflags.h" 19 #include "webrtc/audio_processing/debug.pb.h" 20 #include "webrtc/base/format_macros.h" 21 #include "webrtc/base/scoped_ptr.h" 22 #include "webrtc/modules/audio_processing/test/protobuf_utils.h" 23 #include "webrtc/modules/audio_processing/test/test_utils.h" 24 #include "webrtc/typedefs.h" 25 26 // TODO(andrew): unpack more of the data. 27 DEFINE_string(input_file, "input", "The name of the input stream file."); 28 DEFINE_string(output_file, "ref_out", 29 "The name of the reference output stream file."); 30 DEFINE_string(reverse_file, "reverse", 31 "The name of the reverse input stream file."); 32 DEFINE_string(delay_file, "delay.int32", "The name of the delay file."); 33 DEFINE_string(drift_file, "drift.int32", "The name of the drift file."); 34 DEFINE_string(level_file, "level.int32", "The name of the level file."); 35 DEFINE_string(keypress_file, "keypress.bool", "The name of the keypress file."); 36 DEFINE_string(settings_file, "settings.txt", "The name of the settings file."); 37 DEFINE_bool(full, false, 38 "Unpack the full set of files (normally not needed)."); 39 DEFINE_bool(raw, false, "Write raw data instead of a WAV file."); 40 DEFINE_bool(text, 41 false, 42 "Write non-audio files as text files instead of binary files."); 43 44 #define PRINT_CONFIG(field_name) \ 45 if (msg.has_##field_name()) { \ 46 fprintf(settings_file, " " #field_name ": %d\n", msg.field_name()); \ 47 } 48 49 namespace webrtc { 50 51 using audioproc::Event; 52 using audioproc::ReverseStream; 53 using audioproc::Stream; 54 using audioproc::Init; 55 56 void WriteData(const void* data, size_t size, FILE* file, 57 const std::string& filename) { 58 if (fwrite(data, size, 1, file) != 1) { 59 printf("Error when writing to %s\n", filename.c_str()); 60 exit(1); 61 } 62 } 63 64 int do_main(int argc, char* argv[]) { 65 std::string program_name = argv[0]; 66 std::string usage = "Commandline tool to unpack audioproc debug files.\n" 67 "Example usage:\n" + program_name + " debug_dump.pb\n"; 68 google::SetUsageMessage(usage); 69 google::ParseCommandLineFlags(&argc, &argv, true); 70 71 if (argc < 2) { 72 printf("%s", google::ProgramUsage()); 73 return 1; 74 } 75 76 FILE* debug_file = OpenFile(argv[1], "rb"); 77 78 Event event_msg; 79 int frame_count = 0; 80 size_t reverse_samples_per_channel = 0; 81 size_t input_samples_per_channel = 0; 82 size_t output_samples_per_channel = 0; 83 size_t num_reverse_channels = 0; 84 size_t num_input_channels = 0; 85 size_t num_output_channels = 0; 86 rtc::scoped_ptr<WavWriter> reverse_wav_file; 87 rtc::scoped_ptr<WavWriter> input_wav_file; 88 rtc::scoped_ptr<WavWriter> output_wav_file; 89 rtc::scoped_ptr<RawFile> reverse_raw_file; 90 rtc::scoped_ptr<RawFile> input_raw_file; 91 rtc::scoped_ptr<RawFile> output_raw_file; 92 93 FILE* settings_file = OpenFile(FLAGS_settings_file, "wb"); 94 95 while (ReadMessageFromFile(debug_file, &event_msg)) { 96 if (event_msg.type() == Event::REVERSE_STREAM) { 97 if (!event_msg.has_reverse_stream()) { 98 printf("Corrupt input file: ReverseStream missing.\n"); 99 return 1; 100 } 101 102 const ReverseStream msg = event_msg.reverse_stream(); 103 if (msg.has_data()) { 104 if (FLAGS_raw && !reverse_raw_file) { 105 reverse_raw_file.reset(new RawFile(FLAGS_reverse_file + ".pcm")); 106 } 107 // TODO(aluebs): Replace "num_reverse_channels * 108 // reverse_samples_per_channel" with "msg.data().size() / 109 // sizeof(int16_t)" and so on when this fix in audio_processing has made 110 // it into stable: https://webrtc-codereview.appspot.com/15299004/ 111 WriteIntData(reinterpret_cast<const int16_t*>(msg.data().data()), 112 num_reverse_channels * reverse_samples_per_channel, 113 reverse_wav_file.get(), 114 reverse_raw_file.get()); 115 } else if (msg.channel_size() > 0) { 116 if (FLAGS_raw && !reverse_raw_file) { 117 reverse_raw_file.reset(new RawFile(FLAGS_reverse_file + ".float")); 118 } 119 rtc::scoped_ptr<const float* []> data( 120 new const float* [num_reverse_channels]); 121 for (size_t i = 0; i < num_reverse_channels; ++i) { 122 data[i] = reinterpret_cast<const float*>(msg.channel(i).data()); 123 } 124 WriteFloatData(data.get(), 125 reverse_samples_per_channel, 126 num_reverse_channels, 127 reverse_wav_file.get(), 128 reverse_raw_file.get()); 129 } 130 } else if (event_msg.type() == Event::STREAM) { 131 frame_count++; 132 if (!event_msg.has_stream()) { 133 printf("Corrupt input file: Stream missing.\n"); 134 return 1; 135 } 136 137 const Stream msg = event_msg.stream(); 138 if (msg.has_input_data()) { 139 if (FLAGS_raw && !input_raw_file) { 140 input_raw_file.reset(new RawFile(FLAGS_input_file + ".pcm")); 141 } 142 WriteIntData(reinterpret_cast<const int16_t*>(msg.input_data().data()), 143 num_input_channels * input_samples_per_channel, 144 input_wav_file.get(), 145 input_raw_file.get()); 146 } else if (msg.input_channel_size() > 0) { 147 if (FLAGS_raw && !input_raw_file) { 148 input_raw_file.reset(new RawFile(FLAGS_input_file + ".float")); 149 } 150 rtc::scoped_ptr<const float* []> data( 151 new const float* [num_input_channels]); 152 for (size_t i = 0; i < num_input_channels; ++i) { 153 data[i] = reinterpret_cast<const float*>(msg.input_channel(i).data()); 154 } 155 WriteFloatData(data.get(), 156 input_samples_per_channel, 157 num_input_channels, 158 input_wav_file.get(), 159 input_raw_file.get()); 160 } 161 162 if (msg.has_output_data()) { 163 if (FLAGS_raw && !output_raw_file) { 164 output_raw_file.reset(new RawFile(FLAGS_output_file + ".pcm")); 165 } 166 WriteIntData(reinterpret_cast<const int16_t*>(msg.output_data().data()), 167 num_output_channels * output_samples_per_channel, 168 output_wav_file.get(), 169 output_raw_file.get()); 170 } else if (msg.output_channel_size() > 0) { 171 if (FLAGS_raw && !output_raw_file) { 172 output_raw_file.reset(new RawFile(FLAGS_output_file + ".float")); 173 } 174 rtc::scoped_ptr<const float* []> data( 175 new const float* [num_output_channels]); 176 for (size_t i = 0; i < num_output_channels; ++i) { 177 data[i] = 178 reinterpret_cast<const float*>(msg.output_channel(i).data()); 179 } 180 WriteFloatData(data.get(), 181 output_samples_per_channel, 182 num_output_channels, 183 output_wav_file.get(), 184 output_raw_file.get()); 185 } 186 187 if (FLAGS_full) { 188 if (msg.has_delay()) { 189 static FILE* delay_file = OpenFile(FLAGS_delay_file, "wb"); 190 int32_t delay = msg.delay(); 191 if (FLAGS_text) { 192 fprintf(delay_file, "%d\n", delay); 193 } else { 194 WriteData(&delay, sizeof(delay), delay_file, FLAGS_delay_file); 195 } 196 } 197 198 if (msg.has_drift()) { 199 static FILE* drift_file = OpenFile(FLAGS_drift_file, "wb"); 200 int32_t drift = msg.drift(); 201 if (FLAGS_text) { 202 fprintf(drift_file, "%d\n", drift); 203 } else { 204 WriteData(&drift, sizeof(drift), drift_file, FLAGS_drift_file); 205 } 206 } 207 208 if (msg.has_level()) { 209 static FILE* level_file = OpenFile(FLAGS_level_file, "wb"); 210 int32_t level = msg.level(); 211 if (FLAGS_text) { 212 fprintf(level_file, "%d\n", level); 213 } else { 214 WriteData(&level, sizeof(level), level_file, FLAGS_level_file); 215 } 216 } 217 218 if (msg.has_keypress()) { 219 static FILE* keypress_file = OpenFile(FLAGS_keypress_file, "wb"); 220 bool keypress = msg.keypress(); 221 if (FLAGS_text) { 222 fprintf(keypress_file, "%d\n", keypress); 223 } else { 224 WriteData(&keypress, sizeof(keypress), keypress_file, 225 FLAGS_keypress_file); 226 } 227 } 228 } 229 } else if (event_msg.type() == Event::CONFIG) { 230 if (!event_msg.has_config()) { 231 printf("Corrupt input file: Config missing.\n"); 232 return 1; 233 } 234 const audioproc::Config msg = event_msg.config(); 235 236 fprintf(settings_file, "APM re-config at frame: %d\n", frame_count); 237 238 PRINT_CONFIG(aec_enabled); 239 PRINT_CONFIG(aec_delay_agnostic_enabled); 240 PRINT_CONFIG(aec_drift_compensation_enabled); 241 PRINT_CONFIG(aec_extended_filter_enabled); 242 PRINT_CONFIG(aec_suppression_level); 243 PRINT_CONFIG(aecm_enabled); 244 PRINT_CONFIG(aecm_comfort_noise_enabled); 245 PRINT_CONFIG(aecm_routing_mode); 246 PRINT_CONFIG(agc_enabled); 247 PRINT_CONFIG(agc_mode); 248 PRINT_CONFIG(agc_limiter_enabled); 249 PRINT_CONFIG(noise_robust_agc_enabled); 250 PRINT_CONFIG(hpf_enabled); 251 PRINT_CONFIG(ns_enabled); 252 PRINT_CONFIG(ns_level); 253 PRINT_CONFIG(transient_suppression_enabled); 254 } else if (event_msg.type() == Event::INIT) { 255 if (!event_msg.has_init()) { 256 printf("Corrupt input file: Init missing.\n"); 257 return 1; 258 } 259 260 const Init msg = event_msg.init(); 261 // These should print out zeros if they're missing. 262 fprintf(settings_file, "Init at frame: %d\n", frame_count); 263 int input_sample_rate = msg.sample_rate(); 264 fprintf(settings_file, " Input sample rate: %d\n", input_sample_rate); 265 int output_sample_rate = msg.output_sample_rate(); 266 fprintf(settings_file, " Output sample rate: %d\n", output_sample_rate); 267 int reverse_sample_rate = msg.reverse_sample_rate(); 268 fprintf(settings_file, 269 " Reverse sample rate: %d\n", 270 reverse_sample_rate); 271 num_input_channels = msg.num_input_channels(); 272 fprintf(settings_file, " Input channels: %" PRIuS "\n", 273 num_input_channels); 274 num_output_channels = msg.num_output_channels(); 275 fprintf(settings_file, " Output channels: %" PRIuS "\n", 276 num_output_channels); 277 num_reverse_channels = msg.num_reverse_channels(); 278 fprintf(settings_file, " Reverse channels: %" PRIuS "\n", 279 num_reverse_channels); 280 281 fprintf(settings_file, "\n"); 282 283 if (reverse_sample_rate == 0) { 284 reverse_sample_rate = input_sample_rate; 285 } 286 if (output_sample_rate == 0) { 287 output_sample_rate = input_sample_rate; 288 } 289 290 reverse_samples_per_channel = 291 static_cast<size_t>(reverse_sample_rate / 100); 292 input_samples_per_channel = 293 static_cast<size_t>(input_sample_rate / 100); 294 output_samples_per_channel = 295 static_cast<size_t>(output_sample_rate / 100); 296 297 if (!FLAGS_raw) { 298 // The WAV files need to be reset every time, because they cant change 299 // their sample rate or number of channels. 300 reverse_wav_file.reset(new WavWriter(FLAGS_reverse_file + ".wav", 301 reverse_sample_rate, 302 num_reverse_channels)); 303 input_wav_file.reset(new WavWriter(FLAGS_input_file + ".wav", 304 input_sample_rate, 305 num_input_channels)); 306 output_wav_file.reset(new WavWriter(FLAGS_output_file + ".wav", 307 output_sample_rate, 308 num_output_channels)); 309 } 310 } 311 } 312 313 return 0; 314 } 315 316 } // namespace webrtc 317 318 int main(int argc, char* argv[]) { 319 return webrtc::do_main(argc, argv); 320 } 321