Bug 1024288: Allow aec debug data to be dumped on the fly, with max size r=pkerr a=lmandel
authorRandell Jesup <rjesup@jesup.org>
Thu, 12 Jun 2014 12:20:10 -0400
changeset 208653 5ddb3118d9ae531b2b6d784dd829a88dd5daea66
parent 208652 1f0efff0f0751ca88f946d69bd64b451a9a4974e
child 208654 d59ee55bd050794d52f3d8f6ab17dec123e57045
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspkerr, lmandel
bugs1024288
milestone32.0a2
Bug 1024288: Allow aec debug data to be dumped on the fly, with max size r=pkerr a=lmandel
build/gyp.mozbuild
media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c
media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core_internal.h
media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c
media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h
media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc
--- a/build/gyp.mozbuild
+++ b/build/gyp.mozbuild
@@ -38,17 +38,17 @@ gyp_vars = {
     'arm_neon_optional': 1,
 
     'moz_widget_toolkit_gonk': 0,
     'moz_webrtc_omx': 0,
 
     # (for vp8) chromium sets to 0 also
     'use_temporal_layers': 0,
     # Creates AEC internal sample dump files in current directory
-    # 'aec_debug_dump': 1,
+    'aec_debug_dump': 1,
 
     # codec enable/disables:
     'include_g711': 1,
     'include_opus': 1,
     'include_g722': 0,
     'include_ilbc': 0,
     'include_isac': 0,
     'include_pcm16b': 1,
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core.c
@@ -23,16 +23,21 @@
 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
 #include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
 #include "webrtc/modules/audio_processing/aec/aec_rdft.h"
 #include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
 #include "webrtc/modules/audio_processing/utility/ring_buffer.h"
 #include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
 #include "webrtc/typedefs.h"
 
+extern int AECDebug();
+extern uint32_t AECDebugMaxSize();
+extern void AECDebugEnable(uint32_t enable);
+static void OpenCoreDebugFiles(AecCore* aec, int *instance_count);
+
 // Buffer size (samples)
 static const size_t kBufSizePartitions = 250;  // 1 second of audio in 16 kHz.
 
 // Metrics
 static const int subCountLen = 4;
 static const int countLen = 50;
 
 // Quantities to control H band scaling for SWB input
@@ -206,27 +211,19 @@ int WebRtcAec_CreateAec(AecCore** aecIns
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   aec->far_time_buf =
       WebRtc_CreateBuffer(kBufSizePartitions, sizeof(int16_t) * PART_LEN);
   if (!aec->far_time_buf) {
     WebRtcAec_FreeAec(aec);
     aec = NULL;
     return -1;
   }
-  {
-    char filename[64];
-    sprintf(filename, "aec_far%d.pcm", webrtc_aec_instance_count);
-    aec->farFile = fopen(filename, "wb");
-    sprintf(filename, "aec_near%d.pcm", webrtc_aec_instance_count);
-    aec->nearFile = fopen(filename, "wb");
-    sprintf(filename, "aec_out%d.pcm", webrtc_aec_instance_count);
-    aec->outFile = fopen(filename, "wb");
-    sprintf(filename, "aec_out_linear%d.pcm", webrtc_aec_instance_count);
-    aec->outLinearFile = fopen(filename, "wb");
-  }
+  aec->outLinearFile = aec->outFile = aec->nearFile = aec->farFile = NULL;
+  aec->debugWritten = 0;
+  OpenCoreDebugFiles(aec, &webrtc_aec_instance_count);
 #endif
   aec->delay_estimator_farend =
       WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
   if (aec->delay_estimator_farend == NULL) {
     WebRtcAec_FreeAec(aec);
     aec = NULL;
     return -1;
   }
@@ -251,20 +248,23 @@ int WebRtcAec_FreeAec(AecCore* aec) {
 
   WebRtc_FreeBuffer(aec->nearFrBufH);
   WebRtc_FreeBuffer(aec->outFrBufH);
 
   WebRtc_FreeBuffer(aec->far_buf);
   WebRtc_FreeBuffer(aec->far_buf_windowed);
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   WebRtc_FreeBuffer(aec->far_time_buf);
-  fclose(aec->farFile);
-  fclose(aec->nearFile);
-  fclose(aec->outFile);
-  fclose(aec->outLinearFile);
+  if (aec->farFile) {
+    // we don't let one be open and not the others
+    fclose(aec->farFile);
+    fclose(aec->nearFile);
+    fclose(aec->outFile);
+    fclose(aec->outLinearFile);
+  }
 #endif
   WebRtc_FreeDelayEstimator(aec->delay_estimator);
   WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
 
   free(aec);
   return 0;
 }
 
@@ -843,18 +843,25 @@ static void ProcessBlock(AecCore* aec) {
   }
   memcpy(aec->dBuf + PART_LEN, d, sizeof(float) * PART_LEN);
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   {
     int16_t farend[PART_LEN];
     int16_t* farend_ptr = NULL;
     WebRtc_ReadBuffer(aec->far_time_buf, (void**)&farend_ptr, farend, 1);
-    (void)fwrite(farend_ptr, sizeof(int16_t), PART_LEN, aec->farFile);
-    (void)fwrite(nearend_ptr, sizeof(int16_t), PART_LEN, aec->nearFile);
+    OpenCoreDebugFiles(aec, &webrtc_aec_instance_count);
+    if (aec->farFile) {
+      (void)fwrite(farend_ptr, sizeof(int16_t), PART_LEN, aec->farFile);
+      (void)fwrite(nearend_ptr, sizeof(int16_t), PART_LEN, aec->nearFile);
+      aec->debugWritten += sizeof(int16_t) * PART_LEN;
+      if (aec->debugWritten >= AECDebugMaxSize()) {
+        AECDebugEnable(0);
+      }
+    }
   }
 #endif
 
   // We should always have at least one element stored in |far_buf|.
   assert(WebRtc_available_read(aec->far_buf) > 0);
   WebRtc_ReadBuffer(aec->far_buf, (void**)&xf_ptr, &xf[0][0], 1);
 
   // Near fft
@@ -1001,18 +1008,21 @@ static void ProcessBlock(AecCore* aec) {
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   {
     int16_t eInt16[PART_LEN];
     for (i = 0; i < PART_LEN; i++) {
       eInt16[i] = (int16_t)WEBRTC_SPL_SAT(
           WEBRTC_SPL_WORD16_MAX, e[i], WEBRTC_SPL_WORD16_MIN);
     }
 
-    (void)fwrite(eInt16, sizeof(int16_t), PART_LEN, aec->outLinearFile);
-    (void)fwrite(output, sizeof(int16_t), PART_LEN, aec->outFile);
+    OpenCoreDebugFiles(aec, &webrtc_aec_instance_count);
+    if (aec->outLinearFile) {
+      (void)fwrite(eInt16, sizeof(int16_t), PART_LEN, aec->outLinearFile);
+      (void)fwrite(output, sizeof(int16_t), PART_LEN, aec->outFile);
+    }
   }
 #endif
 }
 
 static void NonLinearProcessing(AecCore* aec, short* output, short* outputH) {
   float efw[2][PART_LEN1], dfw[2][PART_LEN1], xfw[2][PART_LEN1];
   complex_t comfortNoiseHband[PART_LEN1];
   float fft[PART_LEN2];
@@ -1706,8 +1716,52 @@ static void TimeToFrequency(float time_d
   freq_data[0][0] = time_data[0];
   freq_data[0][PART_LEN] = time_data[1];
   for (i = 1; i < PART_LEN; i++) {
     freq_data[0][i] = time_data[2 * i];
     freq_data[1][i] = time_data[2 * i + 1];
   }
 }
 
+#ifdef WEBRTC_AEC_DEBUG_DUMP
+static void
+OpenCoreDebugFiles(AecCore* aec,
+                   int *instance_count)
+{
+  int error = 0;
+  // XXX  If this impacts performance (opening files here), move file open
+  // to Trace::set_aec_debug(), and just grab them here
+  if (AECDebug() && !aec->farFile) {
+    char filename[128];
+    if (!aec->farFile) {
+      sprintf(filename, "aec_far%d.pcm", webrtc_aec_instance_count);
+      aec->farFile = fopen(filename, "wb");
+      sprintf(filename, "aec_near%d.pcm", webrtc_aec_instance_count);
+      aec->nearFile = fopen(filename, "wb");
+      sprintf(filename, "aec_out%d.pcm", webrtc_aec_instance_count);
+      aec->outFile = fopen(filename, "wb");
+      sprintf(filename, "aec_out_linear%d.pcm", webrtc_aec_instance_count);
+      aec->outLinearFile = fopen(filename, "wb");
+      aec->debugWritten = 0;
+      if (!aec->outLinearFile || !aec->outFile || !aec->nearFile || !aec->farFile) {
+        error = 1;
+      }
+    }
+  }
+  if (error ||
+      (!AECDebug() && aec->farFile)) {
+    if (aec->farFile) {
+      fclose(aec->farFile);
+    }
+    if (aec->nearFile) {
+      fclose(aec->nearFile);
+    }
+    if (aec->outFile) {
+      fclose(aec->outFile);
+    }
+    if (aec->outLinearFile) {
+      fclose(aec->outLinearFile);
+    }
+    aec->outLinearFile = aec->outFile = aec->nearFile = aec->farFile = NULL;
+    aec->debugWritten = 0;
+  }
+}
+#endif
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core_internal.h
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/aec_core_internal.h
@@ -128,16 +128,17 @@ struct AecCore {
   int num_partitions;
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   RingBuffer* far_time_buf;
   FILE* farFile;
   FILE* nearFile;
   FILE* outFile;
   FILE* outLinearFile;
+  uint32_t debugWritten;
 #endif
 };
 
 typedef void (*WebRtcAec_FilterFar_t)(AecCore* aec, float yf[2][PART_LEN1]);
 extern WebRtcAec_FilterFar_t WebRtcAec_FilterFar;
 typedef void (*WebRtcAec_ScaleErrorSignal_t)(AecCore* aec,
                                              float ef[2][PART_LEN1]);
 extern WebRtcAec_ScaleErrorSignal_t WebRtcAec_ScaleErrorSignal;
--- a/media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c
+++ b/media/webrtc/trunk/webrtc/modules/audio_processing/aec/echo_cancellation.c
@@ -22,16 +22,21 @@
 
 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
 #include "webrtc/modules/audio_processing/aec/aec_core.h"
 #include "webrtc/modules/audio_processing/aec/aec_resampler.h"
 #include "webrtc/modules/audio_processing/aec/echo_cancellation_internal.h"
 #include "webrtc/modules/audio_processing/utility/ring_buffer.h"
 #include "webrtc/typedefs.h"
 
+extern int AECDebug();
+extern uint32_t AECDebugMaxSize();
+extern void AECDebugEnable(uint32_t enable);
+static void OpenDebugFiles(aecpc_t* aecpc, int *instance_count);
+
 // Measured delays [ms]
 // Device                Chrome  GTP
 // MacBook Air           10
 // MacBook Retina        10      100
 // MacPro                30?
 //
 // Win7 Desktop          70      80?
 // Win7 T430s            110
@@ -160,45 +165,41 @@ int32_t WebRtcAec_Create(void** aecInst)
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   aecpc->far_pre_buf_s16 =
       WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(int16_t));
   if (!aecpc->far_pre_buf_s16) {
     WebRtcAec_Free(aecpc);
     aecpc = NULL;
     return -1;
   }
-  {
-    char filename[64];
-    sprintf(filename, "aec_buf%d.dat", webrtc_aec_instance_count);
-    aecpc->bufFile = fopen(filename, "wb");
-    sprintf(filename, "aec_skew%d.dat", webrtc_aec_instance_count);
-    aecpc->skewFile = fopen(filename, "wb");
-    sprintf(filename, "aec_delay%d.dat", webrtc_aec_instance_count);
-    aecpc->delayFile = fopen(filename, "wb");
-    webrtc_aec_instance_count++;
-  }
+  aecpc->bufFile = aecpc->skewFile = aecpc->delayFile = NULL;
+  OpenDebugFiles(aecpc, &webrtc_aec_instance_count);
+
 #endif
 
   return 0;
 }
 
 int32_t WebRtcAec_Free(void* aecInst) {
   aecpc_t* aecpc = aecInst;
 
   if (aecpc == NULL) {
     return -1;
   }
 
   WebRtc_FreeBuffer(aecpc->far_pre_buf);
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   WebRtc_FreeBuffer(aecpc->far_pre_buf_s16);
-  fclose(aecpc->bufFile);
-  fclose(aecpc->skewFile);
-  fclose(aecpc->delayFile);
+  if (aecpc->bufFile) {
+    // we don't let one be open and not the others
+    fclose(aecpc->bufFile);
+    fclose(aecpc->skewFile);
+    fclose(aecpc->delayFile);
+  }
 #endif
 
   WebRtcAec_FreeAec(aecpc->aec);
   WebRtcAec_FreeResampler(aecpc->resampler);
   free(aecpc);
 
   return 0;
 }
@@ -434,19 +435,22 @@ int32_t WebRtcAec_Process(void* aecInst,
       retVal = -1;
     }
   }
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   {
     int16_t far_buf_size_ms = (int16_t)(WebRtcAec_system_delay(aecpc->aec) /
                                         (sampMsNb * aecpc->rate_factor));
-    (void)fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile);
-    (void)fwrite(
+    OpenDebugFiles(aecpc, &webrtc_aec_instance_count);
+    if (aecpc->bufFile) {
+      (void)fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile);
+      (void)fwrite(
         &aecpc->knownDelay, sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
+    }
   }
 #endif
 
   return retVal;
 }
 
 int WebRtcAec_set_config(void* handle, AecConfig config) {
   aecpc_t* self = (aecpc_t*)handle;
@@ -673,17 +677,20 @@ static int ProcessNormal(aecpc_t* aecpc,
 
       if (aecpc->skew < minSkewEst) {
         aecpc->skew = minSkewEst;
       } else if (aecpc->skew > maxSkewEst) {
         aecpc->skew = maxSkewEst;
       }
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
-      (void)fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
+      OpenDebugFiles(aecpc, &webrtc_aec_instance_count);
+      if (aecpc->skewFile) {
+        (void)fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
+      }
 #endif
     }
   }
 
   nFrames = nrOfSamples / FRAME_LEN;
   nBlocks10ms = nFrames / aecpc->rate_factor;
 
   if (aecpc->startup_phase) {
@@ -963,8 +970,48 @@ static void EstBufDelayExtended(aecpc_t*
     self->timeForDelayChange = 0;
   }
   self->lastDelayDiff = delay_difference;
 
   if (self->timeForDelayChange > 25) {
     self->knownDelay = WEBRTC_SPL_MAX((int)self->filtDelay - 256, 0);
   }
 }
+
+#ifdef WEBRTC_AEC_DEBUG_DUMP
+static void
+OpenDebugFiles(aecpc_t* aecpc,
+               int *instance_count)
+{
+  int error = 0;
+  // XXX  If this impacts performance (opening files here), move file open
+  // to Trace::set_aec_debug(), and just grab them here
+  if (AECDebug() && !aecpc->bufFile) {
+    char filename[128];
+    sprintf(filename, "aec_buf%d.dat", *instance_count);
+    aecpc->bufFile = fopen(filename, "wb");
+    sprintf(filename, "aec_skew%d.dat", *instance_count);
+    aecpc->skewFile = fopen(filename, "wb");
+    sprintf(filename, "aec_delay%d.dat", *instance_count);
+    aecpc->delayFile = fopen(filename, "wb");
+
+    if (!aecpc->bufFile || !aecpc->skewFile || !aecpc->delayFile) {
+      error = 1;
+    } else {
+      (*instance_count)++;
+    }
+  }
+  if (error ||
+      (!AECDebug() && aecpc->bufFile)) {
+    if (aecpc->bufFile) {
+      fclose(aecpc->bufFile);
+    }
+    if (aecpc->skewFile) {
+      fclose(aecpc->skewFile);
+    }
+    if (aecpc->delayFile) {
+      fclose(aecpc->delayFile);
+    }
+    aecpc->bufFile = aecpc->skewFile = aecpc->delayFile = NULL;
+  }
+}
+
+#endif
--- a/media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h
+++ b/media/webrtc/trunk/webrtc/system_wrappers/interface/trace.h
@@ -49,16 +49,22 @@ class Trace {
   // filter parameter is a bitmask where each message type is enumerated by the
   // TraceLevel enumerator. TODO(hellner): why is the TraceLevel enumerator not
   // defined in this file?
   static void set_level_filter(uint32_t filter) { level_filter_ = filter; }
 
   // Returns what type of messages are written to the trace file.
   static uint32_t level_filter() { return level_filter_; }
 
+  // Enable dumping of AEC inputs and outputs.  Can be changed in mid-call
+  static void set_aec_debug(bool enable) { aec_debug_ = enable; }
+  static void set_aec_debug_size(uint32_t size) { aec_debug_size_ = size; }
+  static bool aec_debug() { return aec_debug_; }
+  static uint32_t aec_debug_size() { return aec_debug_size_; }
+
   // Sets the file name. If add_file_counter is false the same file will be
   // reused when it fills up. If it's true a new file with incremented name
   // will be used.
   static int32_t SetTraceFile(const char* file_name,
                               const bool add_file_counter = false);
 
   // Returns the name of the file that the trace is currently writing to.
   static int32_t TraceFile(char file_name[1024]);
@@ -80,13 +86,21 @@ class Trace {
   // TODO(hellner) Why is TraceModule not defined in this file?
   static void Add(const TraceLevel level,
                   const TraceModule module,
                   const int32_t id,
                   const char* msg, ...);
 
  private:
   static uint32_t level_filter_;
+  static bool aec_debug_;
+  static uint32_t aec_debug_size_;
 };
 
 }  // namespace webrtc
 
+extern "C" {
+  extern int AECDebug();
+  extern uint32_t AECDebugMaxSize();
+  extern void AECDebugEnable(uint32_t enable);
+}
+
 #endif  // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_
--- a/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc
+++ b/media/webrtc/trunk/webrtc/system_wrappers/source/trace_impl.cc
@@ -24,22 +24,30 @@
 #include "webrtc/system_wrappers/interface/sleep.h"
 
 #define KEY_LEN_CHARS 31
 
 #ifdef _WIN32
 #pragma warning(disable:4355)
 #endif  // _WIN32
 
+extern "C" {
+  int AECDebug() { return (int) webrtc::Trace::aec_debug(); }
+  uint32_t AECDebugMaxSize() { return webrtc::Trace::aec_debug_size(); }
+  void AECDebugEnable(uint32_t enable) { webrtc::Trace::set_aec_debug(!!enable); }
+}
+
 namespace webrtc {
 
 const int Trace::kBoilerplateLength = 71;
 const int Trace::kTimestampPosition = 13;
 const int Trace::kTimestampLength = 12;
 uint32_t Trace::level_filter_ = kTraceDefault;
+bool Trace::aec_debug_ = false;
+uint32_t Trace::aec_debug_size_ = 4*1024*1024;
 
 // Construct On First Use idiom. Avoids "static initialization order fiasco".
 TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation,
                                      const TraceLevel level) {
   // Sanities to avoid taking lock unless absolutely necessary (for
   // performance reasons). count_operation == kAddRefNoCreate implies that a
   // message will be written to file.
   if ((level != kTraceAll) && (count_operation == kAddRefNoCreate)) {