Line data Source code
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 WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
12 : #define WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
13 :
14 : #include <stdio.h>
15 :
16 : #include <memory>
17 : #include <string>
18 : #include <string.h>
19 : #include <unordered_map>
20 :
21 : #include "webrtc/base/array_view.h"
22 : #include "webrtc/base/constructormagic.h"
23 : #include "webrtc/common_audio/wav_file.h"
24 :
25 : // Check to verify that the define is properly set.
26 : #if !defined(WEBRTC_APM_DEBUG_DUMP) || \
27 : (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1)
28 : #error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1"
29 : #endif
30 :
31 : #if WEBRTC_APM_DEBUG_DUMP == 1
32 : extern "C" {
33 : extern int AECDebug();
34 : extern uint32_t AECDebugMaxSize();
35 : extern void AECDebugEnable(uint32_t enable);
36 : extern void AECDebugFilenameBase(char *buffer, size_t size);
37 : }
38 : #endif
39 :
40 : namespace webrtc {
41 :
42 : #if WEBRTC_APM_DEBUG_DUMP == 1
43 : // Functor used to use as a custom deleter in the map of file pointers to raw
44 : // files.
45 : struct RawFileCloseFunctor {
46 : void operator()(FILE* f) const { if (f) fclose(f); }
47 : };
48 : #endif
49 :
50 : // Class that handles dumping of variables into files.
51 : class ApmDataDumper {
52 : public:
53 : // Constructor that takes an instance index that may
54 : // be used to distinguish data dumped from different
55 : // instances of the code.
56 : explicit ApmDataDumper(int instance_index);
57 :
58 : ~ApmDataDumper();
59 :
60 : // Reinitializes the data dumping such that new versions
61 : // of all files being dumped to are created.
62 0 : void InitiateNewSetOfRecordings() {
63 : #if WEBRTC_APM_DEBUG_DUMP == 1
64 : ++recording_set_index_;
65 : debug_written_ = 0;
66 : #endif
67 0 : }
68 :
69 : // Methods for performing dumping of data of various types into
70 : // various formats.
71 0 : void DumpRaw(const char* name, int v_length, const float* v) {
72 : #if WEBRTC_APM_DEBUG_DUMP == 1
73 : if (AECDebug()) {
74 : FILE* file = GetRawFile(name);
75 : if (file) {
76 : fwrite(v, sizeof(v[0]), v_length, file);
77 : }
78 : }
79 : #endif
80 0 : }
81 :
82 0 : void DumpRaw(const char* name, rtc::ArrayView<const float> v) {
83 : #if WEBRTC_APM_DEBUG_DUMP == 1
84 : DumpRaw(name, v.size(), v.data());
85 : #endif
86 0 : }
87 :
88 : void DumpRaw(const char* name, int v_length, const bool* v) {
89 : #if WEBRTC_APM_DEBUG_DUMP == 1
90 : if (AECDebug()) {
91 : FILE* file = GetRawFile(name);
92 : if (file) {
93 : for (int k = 0; k < v_length; ++k) {
94 : int16_t value = static_cast<int16_t>(v[k]);
95 : fwrite(&value, sizeof(value), 1, file);
96 : }
97 : }
98 : }
99 : #endif
100 : }
101 :
102 : void DumpRaw(const char* name, rtc::ArrayView<const bool> v) {
103 : #if WEBRTC_APM_DEBUG_DUMP == 1
104 : DumpRaw(name, v.size(), v.data());
105 : #endif
106 : }
107 :
108 : void DumpRaw(const char* name, int v_length, const int16_t* v) {
109 : #if WEBRTC_APM_DEBUG_DUMP == 1
110 : if (AECDebug()) {
111 : FILE* file = GetRawFile(name);
112 : if (file) {
113 : fwrite(v, sizeof(v[0]), v_length, file);
114 : }
115 : }
116 : #endif
117 : }
118 :
119 : void DumpRaw(const char* name, rtc::ArrayView<const int16_t> v) {
120 : #if WEBRTC_APM_DEBUG_DUMP == 1
121 : DumpRaw(name, v.size(), v.data());
122 : #endif
123 : }
124 :
125 0 : void DumpRaw(const char* name, int v_length, const int32_t* v) {
126 : #if WEBRTC_APM_DEBUG_DUMP == 1
127 : if (AECDebug()) {
128 : FILE* file = GetRawFile(name);
129 : if (file) {
130 : fwrite(v, sizeof(v[0]), v_length, file);
131 : }
132 : }
133 : #endif
134 0 : }
135 :
136 : void DumpRaw(const char* name, rtc::ArrayView<const int32_t> v) {
137 : #if WEBRTC_APM_DEBUG_DUMP == 1
138 : DumpRaw(name, v.size(), v.data());
139 : #endif
140 : }
141 :
142 0 : void DumpWav(const char* name,
143 : int v_length,
144 : const float* v,
145 : int sample_rate_hz,
146 : int num_channels) {
147 : #if WEBRTC_APM_DEBUG_DUMP == 1
148 : if (AECDebug()) {
149 : WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels);
150 : file->WriteSamples(v, v_length);
151 : // Cheat and use aec_near as a stand-in for "size of the largest file"
152 : // in the dump. We're looking to limit the total time, and that's a
153 : // reasonable stand-in.
154 : if (strcmp(name, "aec_near") == 0) {
155 : updateDebugWritten(v_length * sizeof(float));
156 : }
157 : }
158 : #endif
159 0 : }
160 :
161 0 : void DumpWav(const char* name,
162 : rtc::ArrayView<const float> v,
163 : int sample_rate_hz,
164 : int num_channels) {
165 : #if WEBRTC_APM_DEBUG_DUMP == 1
166 : DumpWav(name, v.size(), v.data(), sample_rate_hz, num_channels);
167 : #endif
168 0 : }
169 :
170 : private:
171 : #if WEBRTC_APM_DEBUG_DUMP == 1
172 : const int instance_index_;
173 : int recording_set_index_ = 0;
174 : std::unordered_map<std::string, std::unique_ptr<FILE, RawFileCloseFunctor>>
175 : raw_files_;
176 : std::unordered_map<std::string, std::unique_ptr<WavWriter>> wav_files_;
177 :
178 : FILE* GetRawFile(const char* name);
179 : WavWriter* GetWavFile(const char* name, int sample_rate_hz, int num_channels);
180 :
181 : uint32_t debug_written_;
182 :
183 : void updateDebugWritten(uint32_t amount) {
184 : debug_written_ += amount;
185 : // Limit largest files to a specific (rough) size, to avoid filling up disk.
186 : if (debug_written_ >= AECDebugMaxSize()) {
187 : AECDebugEnable(0);
188 : }
189 : }
190 :
191 : #endif
192 : RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ApmDataDumper);
193 : };
194 :
195 : } // namespace webrtc
196 :
197 : #endif // WEBRTC_MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_
|