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