• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ReadMessageFromFile(FILE * file,::google::protobuf::MessageLite * msg)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 
main(int argc,char * argv[])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