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