xref: /aosp_15_r20/external/webrtc/modules/audio_processing/logging/apm_data_dumper.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2016 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 #ifndef MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
12 #define MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
13 
14 #include <stdint.h>
15 #include <stdio.h>
16 
17 #if WEBRTC_APM_DEBUG_DUMP == 1
18 #include <memory>
19 #include <string>
20 #include <unordered_map>
21 #endif
22 
23 #include "absl/strings/string_view.h"
24 #include "absl/types/optional.h"
25 #include "api/array_view.h"
26 #if WEBRTC_APM_DEBUG_DUMP == 1
27 #include "common_audio/wav_file.h"
28 #include "rtc_base/checks.h"
29 #include "rtc_base/string_utils.h"
30 #endif
31 
32 // Check to verify that the define is properly set.
33 #if !defined(WEBRTC_APM_DEBUG_DUMP) || \
34     (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1)
35 #error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1"
36 #endif
37 
38 namespace webrtc {
39 
40 #if WEBRTC_APM_DEBUG_DUMP == 1
41 // Functor used to use as a custom deleter in the map of file pointers to raw
42 // files.
43 struct RawFileCloseFunctor {
operatorRawFileCloseFunctor44   void operator()(FILE* f) const { fclose(f); }
45 };
46 #endif
47 
48 // Class that handles dumping of variables into files.
49 class ApmDataDumper {
50  public:
51   // Constructor that takes an instance index that may
52   // be used to distinguish data dumped from different
53   // instances of the code.
54   explicit ApmDataDumper(int instance_index);
55 
56   ApmDataDumper() = delete;
57   ApmDataDumper(const ApmDataDumper&) = delete;
58   ApmDataDumper& operator=(const ApmDataDumper&) = delete;
59 
60   ~ApmDataDumper();
61 
62   // Activates or deactivate the dumping functionality.
SetActivated(bool activated)63   static void SetActivated(bool activated) {
64 #if WEBRTC_APM_DEBUG_DUMP == 1
65     recording_activated_ = activated;
66 #endif
67   }
68 
69   // Returns whether dumping functionality is enabled/available.
IsAvailable()70   static bool IsAvailable() {
71 #if WEBRTC_APM_DEBUG_DUMP == 1
72     return true;
73 #else
74     return false;
75 #endif
76   }
77 
78   // Default dump set.
79   static constexpr size_t kDefaultDumpSet = 0;
80 
81   // Specifies what dump set to use. All dump commands with a different dump set
82   // than the one specified will be discarded. If not specificed, all dump sets
83   // will be used.
SetDumpSetToUse(int dump_set_to_use)84   static void SetDumpSetToUse(int dump_set_to_use) {
85 #if WEBRTC_APM_DEBUG_DUMP == 1
86     dump_set_to_use_ = dump_set_to_use;
87 #endif
88   }
89 
90   // Set an optional output directory.
SetOutputDirectory(absl::string_view output_dir)91   static void SetOutputDirectory(absl::string_view output_dir) {
92 #if WEBRTC_APM_DEBUG_DUMP == 1
93     RTC_CHECK_LT(output_dir.size(), kOutputDirMaxLength);
94     rtc::strcpyn(output_dir_, output_dir.size(), output_dir);
95 #endif
96   }
97 
98   // Reinitializes the data dumping such that new versions
99   // of all files being dumped to are created.
InitiateNewSetOfRecordings()100   void InitiateNewSetOfRecordings() {
101 #if WEBRTC_APM_DEBUG_DUMP == 1
102     ++recording_set_index_;
103 #endif
104   }
105 
106   // Methods for performing dumping of data of various types into
107   // various formats.
108   void DumpRaw(absl::string_view name,
109                double v,
110                int dump_set = kDefaultDumpSet) {
111 #if WEBRTC_APM_DEBUG_DUMP == 1
112     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
113       return;
114 
115     if (recording_activated_) {
116       FILE* file = GetRawFile(name);
117       fwrite(&v, sizeof(v), 1, file);
118     }
119 #endif
120   }
121 
122   void DumpRaw(absl::string_view name,
123                size_t v_length,
124                const double* v,
125                int dump_set = kDefaultDumpSet) {
126 #if WEBRTC_APM_DEBUG_DUMP == 1
127     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
128       return;
129 
130     if (recording_activated_) {
131       FILE* file = GetRawFile(name);
132       fwrite(v, sizeof(v[0]), v_length, file);
133     }
134 #endif
135   }
136 
137   void DumpRaw(absl::string_view name,
138                rtc::ArrayView<const double> v,
139                int dump_set = kDefaultDumpSet) {
140 #if WEBRTC_APM_DEBUG_DUMP == 1
141     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
142       return;
143 
144     if (recording_activated_) {
145       DumpRaw(name, v.size(), v.data());
146     }
147 #endif
148   }
149 
150   void DumpRaw(absl::string_view name,
151                float v,
152                int dump_set = kDefaultDumpSet) {
153 #if WEBRTC_APM_DEBUG_DUMP == 1
154     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
155       return;
156 
157     if (recording_activated_) {
158       FILE* file = GetRawFile(name);
159       fwrite(&v, sizeof(v), 1, file);
160     }
161 #endif
162   }
163 
164   void DumpRaw(absl::string_view name,
165                size_t v_length,
166                const float* v,
167                int dump_set = kDefaultDumpSet) {
168 #if WEBRTC_APM_DEBUG_DUMP == 1
169     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
170       return;
171 
172     if (recording_activated_) {
173       FILE* file = GetRawFile(name);
174       fwrite(v, sizeof(v[0]), v_length, file);
175     }
176 #endif
177   }
178 
179   void DumpRaw(absl::string_view name,
180                rtc::ArrayView<const float> v,
181                int dump_set = kDefaultDumpSet) {
182 #if WEBRTC_APM_DEBUG_DUMP == 1
183     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
184       return;
185 
186     if (recording_activated_) {
187       DumpRaw(name, v.size(), v.data());
188     }
189 #endif
190   }
191 
192   void DumpRaw(absl::string_view name, bool v, int dump_set = kDefaultDumpSet) {
193 #if WEBRTC_APM_DEBUG_DUMP == 1
194     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
195       return;
196 
197     if (recording_activated_) {
198       DumpRaw(name, static_cast<int16_t>(v));
199     }
200 #endif
201   }
202 
203   void DumpRaw(absl::string_view name,
204                size_t v_length,
205                const bool* v,
206                int dump_set = kDefaultDumpSet) {
207 #if WEBRTC_APM_DEBUG_DUMP == 1
208     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
209       return;
210 
211     if (recording_activated_) {
212       FILE* file = GetRawFile(name);
213       for (size_t k = 0; k < v_length; ++k) {
214         int16_t value = static_cast<int16_t>(v[k]);
215         fwrite(&value, sizeof(value), 1, file);
216       }
217     }
218 #endif
219   }
220 
221   void DumpRaw(absl::string_view name,
222                rtc::ArrayView<const bool> v,
223                int dump_set = kDefaultDumpSet) {
224 #if WEBRTC_APM_DEBUG_DUMP == 1
225     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
226       return;
227 
228     if (recording_activated_) {
229       DumpRaw(name, v.size(), v.data());
230     }
231 #endif
232   }
233 
234   void DumpRaw(absl::string_view name,
235                int16_t v,
236                int dump_set = kDefaultDumpSet) {
237 #if WEBRTC_APM_DEBUG_DUMP == 1
238     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
239       return;
240 
241     if (recording_activated_) {
242       FILE* file = GetRawFile(name);
243       fwrite(&v, sizeof(v), 1, file);
244     }
245 #endif
246   }
247 
248   void DumpRaw(absl::string_view name,
249                size_t v_length,
250                const int16_t* v,
251                int dump_set = kDefaultDumpSet) {
252 #if WEBRTC_APM_DEBUG_DUMP == 1
253     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
254       return;
255 
256     if (recording_activated_) {
257       FILE* file = GetRawFile(name);
258       fwrite(v, sizeof(v[0]), v_length, file);
259     }
260 #endif
261   }
262 
263   void DumpRaw(absl::string_view name,
264                rtc::ArrayView<const int16_t> v,
265                int dump_set = kDefaultDumpSet) {
266 #if WEBRTC_APM_DEBUG_DUMP == 1
267     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
268       return;
269 
270     if (recording_activated_) {
271       DumpRaw(name, v.size(), v.data());
272     }
273 #endif
274   }
275 
276   void DumpRaw(absl::string_view name,
277                int32_t v,
278                int dump_set = kDefaultDumpSet) {
279 #if WEBRTC_APM_DEBUG_DUMP == 1
280     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
281       return;
282 
283     if (recording_activated_) {
284       FILE* file = GetRawFile(name);
285       fwrite(&v, sizeof(v), 1, file);
286     }
287 #endif
288   }
289 
290   void DumpRaw(absl::string_view name,
291                size_t v_length,
292                const int32_t* v,
293                int dump_set = kDefaultDumpSet) {
294 #if WEBRTC_APM_DEBUG_DUMP == 1
295     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
296       return;
297 
298     if (recording_activated_) {
299       FILE* file = GetRawFile(name);
300       fwrite(v, sizeof(v[0]), v_length, file);
301     }
302 #endif
303   }
304 
305   void DumpRaw(absl::string_view name,
306                size_t v,
307                int dump_set = kDefaultDumpSet) {
308 #if WEBRTC_APM_DEBUG_DUMP == 1
309     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
310       return;
311 
312     if (recording_activated_) {
313       FILE* file = GetRawFile(name);
314       fwrite(&v, sizeof(v), 1, file);
315     }
316 #endif
317   }
318 
319   void DumpRaw(absl::string_view name,
320                size_t v_length,
321                const size_t* v,
322                int dump_set = kDefaultDumpSet) {
323 #if WEBRTC_APM_DEBUG_DUMP == 1
324     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
325       return;
326 
327     if (recording_activated_) {
328       FILE* file = GetRawFile(name);
329       fwrite(v, sizeof(v[0]), v_length, file);
330     }
331 #endif
332   }
333 
334   void DumpRaw(absl::string_view name,
335                rtc::ArrayView<const int32_t> v,
336                int dump_set = kDefaultDumpSet) {
337 #if WEBRTC_APM_DEBUG_DUMP == 1
338     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
339       return;
340 
341     if (recording_activated_) {
342       DumpRaw(name, v.size(), v.data());
343     }
344 #endif
345   }
346 
347   void DumpRaw(absl::string_view name,
348                rtc::ArrayView<const size_t> v,
349                int dump_set = kDefaultDumpSet) {
350 #if WEBRTC_APM_DEBUG_DUMP == 1
351     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
352       return;
353 
354     DumpRaw(name, v.size(), v.data());
355 #endif
356   }
357 
358   void DumpWav(absl::string_view name,
359                size_t v_length,
360                const float* v,
361                int sample_rate_hz,
362                int num_channels,
363                int dump_set = kDefaultDumpSet) {
364 #if WEBRTC_APM_DEBUG_DUMP == 1
365     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
366       return;
367 
368     if (recording_activated_) {
369       WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels,
370                                    WavFile::SampleFormat::kFloat);
371       file->WriteSamples(v, v_length);
372     }
373 #endif
374   }
375 
376   void DumpWav(absl::string_view name,
377                rtc::ArrayView<const float> v,
378                int sample_rate_hz,
379                int num_channels,
380                int dump_set = kDefaultDumpSet) {
381 #if WEBRTC_APM_DEBUG_DUMP == 1
382     if (dump_set_to_use_ && *dump_set_to_use_ != dump_set)
383       return;
384 
385     if (recording_activated_) {
386       DumpWav(name, v.size(), v.data(), sample_rate_hz, num_channels);
387     }
388 #endif
389   }
390 
391  private:
392 #if WEBRTC_APM_DEBUG_DUMP == 1
393   static bool recording_activated_;
394   static absl::optional<int> dump_set_to_use_;
395   static constexpr size_t kOutputDirMaxLength = 1024;
396   static char output_dir_[kOutputDirMaxLength];
397   const int instance_index_;
398   int recording_set_index_ = 0;
399   std::unordered_map<std::string, std::unique_ptr<FILE, RawFileCloseFunctor>>
400       raw_files_;
401   std::unordered_map<std::string, std::unique_ptr<WavWriter>> wav_files_;
402 
403   FILE* GetRawFile(absl::string_view name);
404   WavWriter* GetWavFile(absl::string_view name,
405                         int sample_rate_hz,
406                         int num_channels,
407                         WavFile::SampleFormat format);
408 #endif
409 };
410 
411 }  // namespace webrtc
412 
413 #endif  // MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
414