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/modules/audio_processing/test/test_utils.h" 21 #include "webrtc/system_wrappers/interface/scoped_ptr.h" 22 #include "webrtc/typedefs.h" 23 24 // TODO(andrew): unpack more of the data. 25 DEFINE_string(input_file, "input", "The name of the input stream file."); 26 DEFINE_string(output_file, "ref_out", 27 "The name of the reference output stream file."); 28 DEFINE_string(reverse_file, "reverse", 29 "The name of the reverse input stream file."); 30 DEFINE_string(delay_file, "delay.int32", "The name of the delay file."); 31 DEFINE_string(drift_file, "drift.int32", "The name of the drift file."); 32 DEFINE_string(level_file, "level.int32", "The name of the level file."); 33 DEFINE_string(keypress_file, "keypress.bool", "The name of the keypress file."); 34 DEFINE_string(settings_file, "settings.txt", "The name of the settings file."); 35 DEFINE_bool(full, false, 36 "Unpack the full set of files (normally not needed)."); 37 DEFINE_bool(raw, false, "Write raw data instead of a WAV file."); 38 39 namespace webrtc { 40 41 using audioproc::Event; 42 using audioproc::ReverseStream; 43 using audioproc::Stream; 44 using audioproc::Init; 45 46 void WriteData(const void* data, size_t size, FILE* file, 47 const std::string& filename) { 48 if (fwrite(data, size, 1, file) != 1) { 49 printf("Error when writing to %s\n", filename.c_str()); 50 exit(1); 51 } 52 } 53 54 int do_main(int argc, char* argv[]) { 55 std::string program_name = argv[0]; 56 std::string usage = "Commandline tool to unpack audioproc debug files.\n" 57 "Example usage:\n" + program_name + " debug_dump.pb\n"; 58 google::SetUsageMessage(usage); 59 google::ParseCommandLineFlags(&argc, &argv, true); 60 61 if (argc < 2) { 62 printf("%s", google::ProgramUsage()); 63 return 1; 64 } 65 66 FILE* debug_file = OpenFile(argv[1], "rb"); 67 68 Event event_msg; 69 int frame_count = 0; 70 int reverse_samples_per_channel = 0; 71 int input_samples_per_channel = 0; 72 int output_samples_per_channel = 0; 73 int num_reverse_channels = 0; 74 int num_input_channels = 0; 75 int num_output_channels = 0; 76 scoped_ptr<WavFile> reverse_wav_file; 77 scoped_ptr<WavFile> input_wav_file; 78 scoped_ptr<WavFile> output_wav_file; 79 scoped_ptr<RawFile> reverse_raw_file; 80 scoped_ptr<RawFile> input_raw_file; 81 scoped_ptr<RawFile> output_raw_file; 82 while (ReadMessageFromFile(debug_file, &event_msg)) { 83 if (event_msg.type() == Event::REVERSE_STREAM) { 84 if (!event_msg.has_reverse_stream()) { 85 printf("Corrupt input file: ReverseStream missing.\n"); 86 return 1; 87 } 88 89 const ReverseStream msg = event_msg.reverse_stream(); 90 if (msg.has_data()) { 91 if (FLAGS_raw && !reverse_raw_file) { 92 reverse_raw_file.reset(new RawFile(FLAGS_reverse_file + ".pcm")); 93 } 94 // TODO(aluebs): Replace "num_reverse_channels * 95 // reverse_samples_per_channel" with "msg.data().size() / 96 // sizeof(int16_t)" and so on when this fix in audio_processing has made 97 // it into stable: https://webrtc-codereview.appspot.com/15299004/ 98 WriteIntData(reinterpret_cast<const int16_t*>(msg.data().data()), 99 num_reverse_channels * reverse_samples_per_channel, 100 reverse_wav_file.get(), 101 reverse_raw_file.get()); 102 } else if (msg.channel_size() > 0) { 103 if (FLAGS_raw && !reverse_raw_file) { 104 reverse_raw_file.reset(new RawFile(FLAGS_reverse_file + ".float")); 105 } 106 scoped_ptr<const float*[]> data(new const float*[num_reverse_channels]); 107 for (int i = 0; i < num_reverse_channels; ++i) { 108 data[i] = reinterpret_cast<const float*>(msg.channel(i).data()); 109 } 110 WriteFloatData(data.get(), 111 reverse_samples_per_channel, 112 num_reverse_channels, 113 reverse_wav_file.get(), 114 reverse_raw_file.get()); 115 } 116 } else if (event_msg.type() == Event::STREAM) { 117 frame_count++; 118 if (!event_msg.has_stream()) { 119 printf("Corrupt input file: Stream missing.\n"); 120 return 1; 121 } 122 123 const Stream msg = event_msg.stream(); 124 if (msg.has_input_data()) { 125 if (FLAGS_raw && !input_raw_file) { 126 input_raw_file.reset(new RawFile(FLAGS_input_file + ".pcm")); 127 } 128 WriteIntData(reinterpret_cast<const int16_t*>(msg.input_data().data()), 129 num_input_channels * input_samples_per_channel, 130 input_wav_file.get(), 131 input_raw_file.get()); 132 } else if (msg.input_channel_size() > 0) { 133 if (FLAGS_raw && !input_raw_file) { 134 input_raw_file.reset(new RawFile(FLAGS_input_file + ".float")); 135 } 136 scoped_ptr<const float*[]> data(new const float*[num_input_channels]); 137 for (int i = 0; i < num_input_channels; ++i) { 138 data[i] = reinterpret_cast<const float*>(msg.input_channel(i).data()); 139 } 140 WriteFloatData(data.get(), 141 input_samples_per_channel, 142 num_input_channels, 143 input_wav_file.get(), 144 input_raw_file.get()); 145 } 146 147 if (msg.has_output_data()) { 148 if (FLAGS_raw && !output_raw_file) { 149 output_raw_file.reset(new RawFile(FLAGS_output_file + ".pcm")); 150 } 151 WriteIntData(reinterpret_cast<const int16_t*>(msg.output_data().data()), 152 num_output_channels * output_samples_per_channel, 153 output_wav_file.get(), 154 output_raw_file.get()); 155 } else if (msg.output_channel_size() > 0) { 156 if (FLAGS_raw && !output_raw_file) { 157 output_raw_file.reset(new RawFile(FLAGS_output_file + ".float")); 158 } 159 scoped_ptr<const float*[]> data(new const float*[num_output_channels]); 160 for (int i = 0; i < num_output_channels; ++i) { 161 data[i] = 162 reinterpret_cast<const float*>(msg.output_channel(i).data()); 163 } 164 WriteFloatData(data.get(), 165 output_samples_per_channel, 166 num_output_channels, 167 output_wav_file.get(), 168 output_raw_file.get()); 169 } 170 171 if (FLAGS_full) { 172 if (msg.has_delay()) { 173 static FILE* delay_file = OpenFile(FLAGS_delay_file, "wb"); 174 int32_t delay = msg.delay(); 175 WriteData(&delay, sizeof(delay), delay_file, FLAGS_delay_file); 176 } 177 178 if (msg.has_drift()) { 179 static FILE* drift_file = OpenFile(FLAGS_drift_file, "wb"); 180 int32_t drift = msg.drift(); 181 WriteData(&drift, sizeof(drift), drift_file, FLAGS_drift_file); 182 } 183 184 if (msg.has_level()) { 185 static FILE* level_file = OpenFile(FLAGS_level_file, "wb"); 186 int32_t level = msg.level(); 187 WriteData(&level, sizeof(level), level_file, FLAGS_level_file); 188 } 189 190 if (msg.has_keypress()) { 191 static FILE* keypress_file = OpenFile(FLAGS_keypress_file, "wb"); 192 bool keypress = msg.keypress(); 193 WriteData(&keypress, sizeof(keypress), keypress_file, 194 FLAGS_keypress_file); 195 } 196 } 197 } else if (event_msg.type() == Event::INIT) { 198 if (!event_msg.has_init()) { 199 printf("Corrupt input file: Init missing.\n"); 200 return 1; 201 } 202 203 static FILE* settings_file = OpenFile(FLAGS_settings_file, "wb"); 204 const Init msg = event_msg.init(); 205 // These should print out zeros if they're missing. 206 fprintf(settings_file, "Init at frame: %d\n", frame_count); 207 int input_sample_rate = msg.sample_rate(); 208 fprintf(settings_file, " Input sample rate: %d\n", input_sample_rate); 209 int output_sample_rate = msg.output_sample_rate(); 210 fprintf(settings_file, " Output sample rate: %d\n", output_sample_rate); 211 int reverse_sample_rate = msg.reverse_sample_rate(); 212 fprintf(settings_file, 213 " Reverse sample rate: %d\n", 214 reverse_sample_rate); 215 num_input_channels = msg.num_input_channels(); 216 fprintf(settings_file, " Input channels: %d\n", num_input_channels); 217 num_output_channels = msg.num_output_channels(); 218 fprintf(settings_file, " Output channels: %d\n", num_output_channels); 219 num_reverse_channels = msg.num_reverse_channels(); 220 fprintf(settings_file, " Reverse channels: %d\n", num_reverse_channels); 221 222 fprintf(settings_file, "\n"); 223 224 if (reverse_sample_rate == 0) { 225 reverse_sample_rate = input_sample_rate; 226 } 227 if (output_sample_rate == 0) { 228 output_sample_rate = input_sample_rate; 229 } 230 231 reverse_samples_per_channel = reverse_sample_rate / 100; 232 input_samples_per_channel = input_sample_rate / 100; 233 output_samples_per_channel = output_sample_rate / 100; 234 235 if (!FLAGS_raw) { 236 // The WAV files need to be reset every time, because they cant change 237 // their sample rate or number of channels. 238 reverse_wav_file.reset(new WavFile(FLAGS_reverse_file + ".wav", 239 reverse_sample_rate, 240 num_reverse_channels)); 241 input_wav_file.reset(new WavFile(FLAGS_input_file + ".wav", 242 input_sample_rate, 243 num_input_channels)); 244 output_wav_file.reset(new WavFile(FLAGS_output_file + ".wav", 245 output_sample_rate, 246 num_output_channels)); 247 } 248 } 249 } 250 251 return 0; 252 } 253 254 } // namespace webrtc 255 256 int main(int argc, char* argv[]) { 257 return webrtc::do_main(argc, argv); 258 } 259