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 #include <string.h> 17 18 #include <string> 19 #if WEBRTC_APM_DEBUG_DUMP == 1 20 #include <memory> 21 #include <unordered_map> 22 #endif 23 24 #include "api/array_view.h" 25 #if WEBRTC_APM_DEBUG_DUMP == 1 26 #include "common_audio/wav_file.h" 27 #include "rtc_base/checks.h" 28 #endif 29 #include "rtc_base/constructor_magic.h" 30 31 // Check to verify that the define is properly set. 32 #if !defined(WEBRTC_APM_DEBUG_DUMP) || \ 33 (WEBRTC_APM_DEBUG_DUMP != 0 && WEBRTC_APM_DEBUG_DUMP != 1) 34 #error "Set WEBRTC_APM_DEBUG_DUMP to either 0 or 1" 35 #endif 36 37 namespace webrtc { 38 39 #if WEBRTC_APM_DEBUG_DUMP == 1 40 // Functor used to use as a custom deleter in the map of file pointers to raw 41 // files. 42 struct RawFileCloseFunctor { operatorRawFileCloseFunctor43 void operator()(FILE* f) const { fclose(f); } 44 }; 45 #endif 46 47 // Class that handles dumping of variables into files. 48 class ApmDataDumper { 49 public: 50 // Constructor that takes an instance index that may 51 // be used to distinguish data dumped from different 52 // instances of the code. 53 explicit ApmDataDumper(int instance_index); 54 55 ~ApmDataDumper(); 56 57 // Activates or deactivate the dumping functionality. SetActivated(bool activated)58 static void SetActivated(bool activated) { 59 #if WEBRTC_APM_DEBUG_DUMP == 1 60 recording_activated_ = activated; 61 #endif 62 } 63 64 // Set an optional output directory. SetOutputDirectory(const std::string & output_dir)65 static void SetOutputDirectory(const std::string& output_dir) { 66 #if WEBRTC_APM_DEBUG_DUMP == 1 67 RTC_CHECK_LT(output_dir.size(), kOutputDirMaxLength); 68 strncpy(output_dir_, output_dir.c_str(), output_dir.size()); 69 #endif 70 } 71 72 // Reinitializes the data dumping such that new versions 73 // of all files being dumped to are created. InitiateNewSetOfRecordings()74 void InitiateNewSetOfRecordings() { 75 #if WEBRTC_APM_DEBUG_DUMP == 1 76 ++recording_set_index_; 77 #endif 78 } 79 80 // Methods for performing dumping of data of various types into 81 // various formats. DumpRaw(const char * name,double v)82 void DumpRaw(const char* name, double v) { 83 #if WEBRTC_APM_DEBUG_DUMP == 1 84 if (recording_activated_) { 85 FILE* file = GetRawFile(name); 86 fwrite(&v, sizeof(v), 1, file); 87 } 88 #endif 89 } 90 DumpRaw(const char * name,size_t v_length,const double * v)91 void DumpRaw(const char* name, size_t v_length, const double* v) { 92 #if WEBRTC_APM_DEBUG_DUMP == 1 93 if (recording_activated_) { 94 FILE* file = GetRawFile(name); 95 fwrite(v, sizeof(v[0]), v_length, file); 96 } 97 #endif 98 } 99 DumpRaw(const char * name,rtc::ArrayView<const double> v)100 void DumpRaw(const char* name, rtc::ArrayView<const double> v) { 101 #if WEBRTC_APM_DEBUG_DUMP == 1 102 if (recording_activated_) { 103 DumpRaw(name, v.size(), v.data()); 104 } 105 #endif 106 } 107 DumpRaw(const char * name,float v)108 void DumpRaw(const char* name, float v) { 109 #if WEBRTC_APM_DEBUG_DUMP == 1 110 if (recording_activated_) { 111 FILE* file = GetRawFile(name); 112 fwrite(&v, sizeof(v), 1, file); 113 } 114 #endif 115 } 116 DumpRaw(const char * name,size_t v_length,const float * v)117 void DumpRaw(const char* name, size_t v_length, const float* v) { 118 #if WEBRTC_APM_DEBUG_DUMP == 1 119 if (recording_activated_) { 120 FILE* file = GetRawFile(name); 121 fwrite(v, sizeof(v[0]), v_length, file); 122 } 123 #endif 124 } 125 DumpRaw(const char * name,rtc::ArrayView<const float> v)126 void DumpRaw(const char* name, rtc::ArrayView<const float> v) { 127 #if WEBRTC_APM_DEBUG_DUMP == 1 128 if (recording_activated_) { 129 DumpRaw(name, v.size(), v.data()); 130 } 131 #endif 132 } 133 DumpRaw(const char * name,bool v)134 void DumpRaw(const char* name, bool v) { 135 #if WEBRTC_APM_DEBUG_DUMP == 1 136 if (recording_activated_) { 137 DumpRaw(name, static_cast<int16_t>(v)); 138 } 139 #endif 140 } 141 DumpRaw(const char * name,size_t v_length,const bool * v)142 void DumpRaw(const char* name, size_t v_length, const bool* v) { 143 #if WEBRTC_APM_DEBUG_DUMP == 1 144 if (recording_activated_) { 145 FILE* file = GetRawFile(name); 146 for (size_t k = 0; k < v_length; ++k) { 147 int16_t value = static_cast<int16_t>(v[k]); 148 fwrite(&value, sizeof(value), 1, file); 149 } 150 } 151 #endif 152 } 153 DumpRaw(const char * name,rtc::ArrayView<const bool> v)154 void DumpRaw(const char* name, rtc::ArrayView<const bool> v) { 155 #if WEBRTC_APM_DEBUG_DUMP == 1 156 if (recording_activated_) { 157 DumpRaw(name, v.size(), v.data()); 158 } 159 #endif 160 } 161 DumpRaw(const char * name,int16_t v)162 void DumpRaw(const char* name, int16_t v) { 163 #if WEBRTC_APM_DEBUG_DUMP == 1 164 if (recording_activated_) { 165 FILE* file = GetRawFile(name); 166 fwrite(&v, sizeof(v), 1, file); 167 } 168 #endif 169 } 170 DumpRaw(const char * name,size_t v_length,const int16_t * v)171 void DumpRaw(const char* name, size_t v_length, const int16_t* v) { 172 #if WEBRTC_APM_DEBUG_DUMP == 1 173 if (recording_activated_) { 174 FILE* file = GetRawFile(name); 175 fwrite(v, sizeof(v[0]), v_length, file); 176 } 177 #endif 178 } 179 DumpRaw(const char * name,rtc::ArrayView<const int16_t> v)180 void DumpRaw(const char* name, rtc::ArrayView<const int16_t> v) { 181 #if WEBRTC_APM_DEBUG_DUMP == 1 182 if (recording_activated_) { 183 DumpRaw(name, v.size(), v.data()); 184 } 185 #endif 186 } 187 DumpRaw(const char * name,int32_t v)188 void DumpRaw(const char* name, int32_t v) { 189 #if WEBRTC_APM_DEBUG_DUMP == 1 190 if (recording_activated_) { 191 FILE* file = GetRawFile(name); 192 fwrite(&v, sizeof(v), 1, file); 193 } 194 #endif 195 } 196 DumpRaw(const char * name,size_t v_length,const int32_t * v)197 void DumpRaw(const char* name, size_t v_length, const int32_t* v) { 198 #if WEBRTC_APM_DEBUG_DUMP == 1 199 if (recording_activated_) { 200 FILE* file = GetRawFile(name); 201 fwrite(v, sizeof(v[0]), v_length, file); 202 } 203 #endif 204 } 205 DumpRaw(const char * name,size_t v)206 void DumpRaw(const char* name, size_t v) { 207 #if WEBRTC_APM_DEBUG_DUMP == 1 208 if (recording_activated_) { 209 FILE* file = GetRawFile(name); 210 fwrite(&v, sizeof(v), 1, file); 211 } 212 #endif 213 } 214 DumpRaw(const char * name,size_t v_length,const size_t * v)215 void DumpRaw(const char* name, size_t v_length, const size_t* v) { 216 #if WEBRTC_APM_DEBUG_DUMP == 1 217 if (recording_activated_) { 218 FILE* file = GetRawFile(name); 219 fwrite(v, sizeof(v[0]), v_length, file); 220 } 221 #endif 222 } 223 DumpRaw(const char * name,rtc::ArrayView<const int32_t> v)224 void DumpRaw(const char* name, rtc::ArrayView<const int32_t> v) { 225 #if WEBRTC_APM_DEBUG_DUMP == 1 226 if (recording_activated_) { 227 DumpRaw(name, v.size(), v.data()); 228 } 229 #endif 230 } 231 DumpRaw(const char * name,rtc::ArrayView<const size_t> v)232 void DumpRaw(const char* name, rtc::ArrayView<const size_t> v) { 233 #if WEBRTC_APM_DEBUG_DUMP == 1 234 DumpRaw(name, v.size(), v.data()); 235 #endif 236 } 237 DumpWav(const char * name,size_t v_length,const float * v,int sample_rate_hz,int num_channels)238 void DumpWav(const char* name, 239 size_t v_length, 240 const float* v, 241 int sample_rate_hz, 242 int num_channels) { 243 #if WEBRTC_APM_DEBUG_DUMP == 1 244 if (recording_activated_) { 245 WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels, 246 WavFile::SampleFormat::kFloat); 247 file->WriteSamples(v, v_length); 248 } 249 #endif 250 } 251 DumpWav(const char * name,rtc::ArrayView<const float> v,int sample_rate_hz,int num_channels)252 void DumpWav(const char* name, 253 rtc::ArrayView<const float> v, 254 int sample_rate_hz, 255 int num_channels) { 256 #if WEBRTC_APM_DEBUG_DUMP == 1 257 if (recording_activated_) { 258 DumpWav(name, v.size(), v.data(), sample_rate_hz, num_channels); 259 } 260 #endif 261 } 262 263 private: 264 #if WEBRTC_APM_DEBUG_DUMP == 1 265 static bool recording_activated_; 266 static constexpr size_t kOutputDirMaxLength = 1024; 267 static char output_dir_[kOutputDirMaxLength]; 268 const int instance_index_; 269 int recording_set_index_ = 0; 270 std::unordered_map<std::string, std::unique_ptr<FILE, RawFileCloseFunctor>> 271 raw_files_; 272 std::unordered_map<std::string, std::unique_ptr<WavWriter>> wav_files_; 273 274 FILE* GetRawFile(const char* name); 275 WavWriter* GetWavFile(const char* name, 276 int sample_rate_hz, 277 int num_channels, 278 WavFile::SampleFormat format); 279 #endif 280 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ApmDataDumper); 281 }; 282 283 } // namespace webrtc 284 285 #endif // MODULES_AUDIO_PROCESSING_LOGGING_APM_DATA_DUMPER_H_ 286