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/scoped_ptr.h" 21 #include "webrtc/modules/audio_processing/test/test_utils.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 rtc::scoped_ptr<WavWriter> reverse_wav_file; 77 rtc::scoped_ptr<WavWriter> input_wav_file; 78 rtc::scoped_ptr<WavWriter> output_wav_file; 79 rtc::scoped_ptr<RawFile> reverse_raw_file; 80 rtc::scoped_ptr<RawFile> input_raw_file; 81 rtc::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 rtc::scoped_ptr<const float* []> data( 107 new const float* [num_reverse_channels]); 108 for (int i = 0; i < num_reverse_channels; ++i) { 109 data[i] = reinterpret_cast<const float*>(msg.channel(i).data()); 110 } 111 WriteFloatData(data.get(), 112 reverse_samples_per_channel, 113 num_reverse_channels, 114 reverse_wav_file.get(), 115 reverse_raw_file.get()); 116 } 117 } else if (event_msg.type() == Event::STREAM) { 118 frame_count++; 119 if (!event_msg.has_stream()) { 120 printf("Corrupt input file: Stream missing.\n"); 121 return 1; 122 } 123 124 const Stream msg = event_msg.stream(); 125 if (msg.has_input_data()) { 126 if (FLAGS_raw && !input_raw_file) { 127 input_raw_file.reset(new RawFile(FLAGS_input_file + ".pcm")); 128 } 129 WriteIntData(reinterpret_cast<const int16_t*>(msg.input_data().data()), 130 num_input_channels * input_samples_per_channel, 131 input_wav_file.get(), 132 input_raw_file.get()); 133 } else if (msg.input_channel_size() > 0) { 134 if (FLAGS_raw && !input_raw_file) { 135 input_raw_file.reset(new RawFile(FLAGS_input_file + ".float")); 136 } 137 rtc::scoped_ptr<const float* []> data( 138 new const float* [num_input_channels]); 139 for (int i = 0; i < num_input_channels; ++i) { 140 data[i] = reinterpret_cast<const float*>(msg.input_channel(i).data()); 141 } 142 WriteFloatData(data.get(), 143 input_samples_per_channel, 144 num_input_channels, 145 input_wav_file.get(), 146 input_raw_file.get()); 147 } 148 149 if (msg.has_output_data()) { 150 if (FLAGS_raw && !output_raw_file) { 151 output_raw_file.reset(new RawFile(FLAGS_output_file + ".pcm")); 152 } 153 WriteIntData(reinterpret_cast<const int16_t*>(msg.output_data().data()), 154 num_output_channels * output_samples_per_channel, 155 output_wav_file.get(), 156 output_raw_file.get()); 157 } else if (msg.output_channel_size() > 0) { 158 if (FLAGS_raw && !output_raw_file) { 159 output_raw_file.reset(new RawFile(FLAGS_output_file + ".float")); 160 } 161 rtc::scoped_ptr<const float* []> data( 162 new const float* [num_output_channels]); 163 for (int i = 0; i < num_output_channels; ++i) { 164 data[i] = 165 reinterpret_cast<const float*>(msg.output_channel(i).data()); 166 } 167 WriteFloatData(data.get(), 168 output_samples_per_channel, 169 num_output_channels, 170 output_wav_file.get(), 171 output_raw_file.get()); 172 } 173 174 if (FLAGS_full) { 175 if (msg.has_delay()) { 176 static FILE* delay_file = OpenFile(FLAGS_delay_file, "wb"); 177 int32_t delay = msg.delay(); 178 WriteData(&delay, sizeof(delay), delay_file, FLAGS_delay_file); 179 } 180 181 if (msg.has_drift()) { 182 static FILE* drift_file = OpenFile(FLAGS_drift_file, "wb"); 183 int32_t drift = msg.drift(); 184 WriteData(&drift, sizeof(drift), drift_file, FLAGS_drift_file); 185 } 186 187 if (msg.has_level()) { 188 static FILE* level_file = OpenFile(FLAGS_level_file, "wb"); 189 int32_t level = msg.level(); 190 WriteData(&level, sizeof(level), level_file, FLAGS_level_file); 191 } 192 193 if (msg.has_keypress()) { 194 static FILE* keypress_file = OpenFile(FLAGS_keypress_file, "wb"); 195 bool keypress = msg.keypress(); 196 WriteData(&keypress, sizeof(keypress), keypress_file, 197 FLAGS_keypress_file); 198 } 199 } 200 } else if (event_msg.type() == Event::INIT) { 201 if (!event_msg.has_init()) { 202 printf("Corrupt input file: Init missing.\n"); 203 return 1; 204 } 205 206 static FILE* settings_file = OpenFile(FLAGS_settings_file, "wb"); 207 const Init msg = event_msg.init(); 208 // These should print out zeros if they're missing. 209 fprintf(settings_file, "Init at frame: %d\n", frame_count); 210 int input_sample_rate = msg.sample_rate(); 211 fprintf(settings_file, " Input sample rate: %d\n", input_sample_rate); 212 int output_sample_rate = msg.output_sample_rate(); 213 fprintf(settings_file, " Output sample rate: %d\n", output_sample_rate); 214 int reverse_sample_rate = msg.reverse_sample_rate(); 215 fprintf(settings_file, 216 " Reverse sample rate: %d\n", 217 reverse_sample_rate); 218 num_input_channels = msg.num_input_channels(); 219 fprintf(settings_file, " Input channels: %d\n", num_input_channels); 220 num_output_channels = msg.num_output_channels(); 221 fprintf(settings_file, " Output channels: %d\n", num_output_channels); 222 num_reverse_channels = msg.num_reverse_channels(); 223 fprintf(settings_file, " Reverse channels: %d\n", num_reverse_channels); 224 225 fprintf(settings_file, "\n"); 226 227 if (reverse_sample_rate == 0) { 228 reverse_sample_rate = input_sample_rate; 229 } 230 if (output_sample_rate == 0) { 231 output_sample_rate = input_sample_rate; 232 } 233 234 reverse_samples_per_channel = reverse_sample_rate / 100; 235 input_samples_per_channel = input_sample_rate / 100; 236 output_samples_per_channel = output_sample_rate / 100; 237 238 if (!FLAGS_raw) { 239 // The WAV files need to be reset every time, because they cant change 240 // their sample rate or number of channels. 241 reverse_wav_file.reset(new WavWriter(FLAGS_reverse_file + ".wav", 242 reverse_sample_rate, 243 num_reverse_channels)); 244 input_wav_file.reset(new WavWriter(FLAGS_input_file + ".wav", 245 input_sample_rate, 246 num_input_channels)); 247 output_wav_file.reset(new WavWriter(FLAGS_output_file + ".wav", 248 output_sample_rate, 249 num_output_channels)); 250 } 251 } 252 } 253 254 return 0; 255 } 256 257 } // namespace webrtc 258 259 int main(int argc, char* argv[]) { 260 return webrtc::do_main(argc, argv); 261 } 262