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 "google/gflags.h" 19 #include "scoped_ptr.h" 20 #include "typedefs.h" 21 #include "webrtc/audio_processing/debug.pb.h" 22 23 using webrtc::scoped_array; 24 25 using webrtc::audioproc::Event; 26 using webrtc::audioproc::ReverseStream; 27 using webrtc::audioproc::Stream; 28 using webrtc::audioproc::Init; 29 30 // TODO(andrew): unpack more of the data. 31 DEFINE_string(input_file, "input.pcm", "The name of the input stream file."); 32 DEFINE_string(output_file, "ref_out.pcm", 33 "The name of the reference output stream file."); 34 DEFINE_string(reverse_file, "reverse.pcm", 35 "The name of the reverse input stream file."); 36 DEFINE_string(delay_file, "delay.int32", "The name of the delay file."); 37 DEFINE_string(drift_file, "drift.int32", "The name of the drift file."); 38 DEFINE_string(level_file, "level.int32", "The name of the level file."); 39 DEFINE_string(settings_file, "settings.txt", "The name of the settings file."); 40 DEFINE_bool(full, false, 41 "Unpack the full set of files (normally not needed)."); 42 43 // TODO(andrew): move this to a helper class to share with process_test.cc? 44 // Returns true on success, false on error or end-of-file. 45 bool ReadMessageFromFile(FILE* file, 46 ::google::protobuf::MessageLite* msg) { 47 // The "wire format" for the size is little-endian. 48 // Assume process_test is running on a little-endian machine. 49 int32_t size = 0; 50 if (fread(&size, sizeof(int32_t), 1, file) != 1) { 51 return false; 52 } 53 if (size <= 0) { 54 return false; 55 } 56 const size_t usize = static_cast<size_t>(size); 57 58 scoped_array<char> array(new char[usize]); 59 if (fread(array.get(), sizeof(char), usize, file) != usize) { 60 return false; 61 } 62 63 msg->Clear(); 64 return msg->ParseFromArray(array.get(), usize); 65 } 66 67 int main(int argc, char* argv[]) { 68 std::string program_name = argv[0]; 69 std::string usage = "Commandline tool to unpack audioproc debug files.\n" 70 "Example usage:\n" + program_name + " debug_dump.pb\n"; 71 google::SetUsageMessage(usage); 72 google::ParseCommandLineFlags(&argc, &argv, true); 73 74 if (argc < 2) { 75 printf("%s", google::ProgramUsage()); 76 return 1; 77 } 78 79 FILE* debug_file = fopen(argv[1], "rb"); 80 if (debug_file == NULL) { 81 printf("Unable to open %s\n", argv[1]); 82 return 1; 83 } 84 FILE* input_file = fopen(FLAGS_input_file.c_str(), "wb"); 85 if (input_file == NULL) { 86 printf("Unable to open %s\n", FLAGS_input_file.c_str()); 87 return 1; 88 } 89 FILE* output_file = fopen(FLAGS_output_file.c_str(), "wb"); 90 if (output_file == NULL) { 91 printf("Unable to open %s\n", FLAGS_output_file.c_str()); 92 return 1; 93 } 94 FILE* reverse_file = fopen(FLAGS_reverse_file.c_str(), "wb"); 95 if (reverse_file == NULL) { 96 printf("Unable to open %s\n", FLAGS_reverse_file.c_str()); 97 return 1; 98 } 99 FILE* settings_file = fopen(FLAGS_settings_file.c_str(), "wb"); 100 if (settings_file == NULL) { 101 printf("Unable to open %s\n", FLAGS_settings_file.c_str()); 102 return 1; 103 } 104 105 FILE* delay_file = NULL; 106 FILE* drift_file = NULL; 107 FILE* level_file = NULL; 108 if (FLAGS_full) { 109 delay_file = fopen(FLAGS_delay_file.c_str(), "wb"); 110 if (delay_file == NULL) { 111 printf("Unable to open %s\n", FLAGS_delay_file.c_str()); 112 return 1; 113 } 114 drift_file = fopen(FLAGS_drift_file.c_str(), "wb"); 115 if (drift_file == NULL) { 116 printf("Unable to open %s\n", FLAGS_drift_file.c_str()); 117 return 1; 118 } 119 level_file = fopen(FLAGS_level_file.c_str(), "wb"); 120 if (level_file == NULL) { 121 printf("Unable to open %s\n", FLAGS_level_file.c_str()); 122 return 1; 123 } 124 } 125 126 Event event_msg; 127 int frame_count = 0; 128 while (ReadMessageFromFile(debug_file, &event_msg)) { 129 if (event_msg.type() == Event::REVERSE_STREAM) { 130 if (!event_msg.has_reverse_stream()) { 131 printf("Corrupted input file: ReverseStream missing.\n"); 132 return 1; 133 } 134 135 const ReverseStream msg = event_msg.reverse_stream(); 136 if (msg.has_data()) { 137 if (fwrite(msg.data().data(), msg.data().size(), 1, reverse_file) != 138 1) { 139 printf("Error when writing to %s\n", FLAGS_reverse_file.c_str()); 140 return 1; 141 } 142 } 143 } else if (event_msg.type() == Event::STREAM) { 144 frame_count++; 145 if (!event_msg.has_stream()) { 146 printf("Corrupted input file: Stream missing.\n"); 147 return 1; 148 } 149 150 const Stream msg = event_msg.stream(); 151 if (msg.has_input_data()) { 152 if (fwrite(msg.input_data().data(), msg.input_data().size(), 1, 153 input_file) != 1) { 154 printf("Error when writing to %s\n", FLAGS_input_file.c_str()); 155 return 1; 156 } 157 } 158 159 if (msg.has_output_data()) { 160 if (fwrite(msg.output_data().data(), msg.output_data().size(), 1, 161 output_file) != 1) { 162 printf("Error when writing to %s\n", FLAGS_output_file.c_str()); 163 return 1; 164 } 165 } 166 167 if (FLAGS_full) { 168 if (msg.has_delay()) { 169 int32_t delay = msg.delay(); 170 if (fwrite(&delay, sizeof(int32_t), 1, delay_file) != 1) { 171 printf("Error when writing to %s\n", FLAGS_delay_file.c_str()); 172 return 1; 173 } 174 } 175 176 if (msg.has_drift()) { 177 int32_t drift = msg.drift(); 178 if (fwrite(&drift, sizeof(int32_t), 1, drift_file) != 1) { 179 printf("Error when writing to %s\n", FLAGS_drift_file.c_str()); 180 return 1; 181 } 182 } 183 184 if (msg.has_level()) { 185 int32_t level = msg.level(); 186 if (fwrite(&level, sizeof(int32_t), 1, level_file) != 1) { 187 printf("Error when writing to %s\n", FLAGS_level_file.c_str()); 188 return 1; 189 } 190 } 191 } 192 } else if (event_msg.type() == Event::INIT) { 193 if (!event_msg.has_init()) { 194 printf("Corrupted input file: Init missing.\n"); 195 return 1; 196 } 197 198 const Init msg = event_msg.init(); 199 // These should print out zeros if they're missing. 200 fprintf(settings_file, "Init at frame: %d\n", frame_count); 201 fprintf(settings_file, " Sample rate: %d\n", msg.sample_rate()); 202 fprintf(settings_file, " Device sample rate: %d\n", 203 msg.device_sample_rate()); 204 fprintf(settings_file, " Input channels: %d\n", 205 msg.num_input_channels()); 206 fprintf(settings_file, " Output channels: %d\n", 207 msg.num_output_channels()); 208 fprintf(settings_file, " Reverse channels: %d\n", 209 msg.num_reverse_channels()); 210 211 fprintf(settings_file, "\n"); 212 } 213 } 214 215 return 0; 216 } 217