Fix WEBRTC_AEC_DEBUG_DUMP (broken by int16->float conversion)

And in the process, make it dump WAV files instead of raw PCM.

R=andrew@webrtc.org, bjornv@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/19089004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6959 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_audio/wav_writer.cc b/webrtc/common_audio/wav_writer.cc
index e571473..f3b8118 100644
--- a/webrtc/common_audio/wav_writer.cc
+++ b/webrtc/common_audio/wav_writer.cc
@@ -101,3 +101,15 @@
                          size_t num_samples) {
   reinterpret_cast<webrtc::WavFile*>(wf)->WriteSamples(samples, num_samples);
 }
+
+int rtc_WavSampleRate(const rtc_WavFile* wf) {
+  return reinterpret_cast<const webrtc::WavFile*>(wf)->sample_rate();
+}
+
+int rtc_WavNumChannels(const rtc_WavFile* wf) {
+  return reinterpret_cast<const webrtc::WavFile*>(wf)->num_channels();
+}
+
+uint32_t rtc_WavNumSamples(const rtc_WavFile* wf) {
+  return reinterpret_cast<const webrtc::WavFile*>(wf)->num_samples();
+}
diff --git a/webrtc/common_audio/wav_writer.h b/webrtc/common_audio/wav_writer.h
index a8fee51..e058265 100644
--- a/webrtc/common_audio/wav_writer.h
+++ b/webrtc/common_audio/wav_writer.h
@@ -34,6 +34,10 @@
   // interleaved channels.
   void WriteSamples(const float* samples, size_t num_samples);
 
+  int sample_rate() const { return sample_rate_; }
+  int num_channels() const { return num_channels_; }
+  uint32_t num_samples() const { return num_samples_; }
+
  private:
   void WriteSamples(const int16_t* samples, size_t num_samples);
   void Close();
@@ -57,6 +61,9 @@
 void rtc_WavWriteSamples(rtc_WavFile* wf,
                          const float* samples,
                          size_t num_samples);
+int rtc_WavSampleRate(const rtc_WavFile* wf);
+int rtc_WavNumChannels(const rtc_WavFile* wf);
+uint32_t rtc_WavNumSamples(const rtc_WavFile* wf);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/webrtc/common_audio/wav_writer_unittest.cc b/webrtc/common_audio/wav_writer_unittest.cc
index 9efe96e..9c593be 100644
--- a/webrtc/common_audio/wav_writer_unittest.cc
+++ b/webrtc/common_audio/wav_writer_unittest.cc
@@ -25,10 +25,14 @@
 // Write a tiny WAV file with the C++ interface and verify the result.
 TEST(WavWriterTest, CPP) {
   const std::string outfile = webrtc::test::OutputPath() + "wavtest1.wav";
-  static const int kNumSamples = 3;
+  static const uint32_t kNumSamples = 3;
   {
     webrtc::WavFile w(outfile, 14099, 1);
+    EXPECT_EQ(14099, w.sample_rate());
+    EXPECT_EQ(1, w.num_channels());
+    EXPECT_EQ(0u, w.num_samples());
     w.WriteSamples(kSamples, kNumSamples);
+    EXPECT_EQ(kNumSamples, w.num_samples());
   }
   static const uint8_t kExpectedContents[] = {
     'R', 'I', 'F', 'F',
@@ -64,9 +68,14 @@
 TEST(WavWriterTest, C) {
   const std::string outfile = webrtc::test::OutputPath() + "wavtest2.wav";
   rtc_WavFile *w = rtc_WavOpen(outfile.c_str(), 11904, 2);
-  static const int kNumSamples = 4;
+  EXPECT_EQ(11904, rtc_WavSampleRate(w));
+  EXPECT_EQ(2, rtc_WavNumChannels(w));
+  EXPECT_EQ(0u, rtc_WavNumSamples(w));
+  static const uint32_t kNumSamples = 4;
   rtc_WavWriteSamples(w, &kSamples[0], 2);
+  EXPECT_EQ(2u, rtc_WavNumSamples(w));
   rtc_WavWriteSamples(w, &kSamples[2], kNumSamples - 2);
+  EXPECT_EQ(kNumSamples, rtc_WavNumSamples(w));
   rtc_WavClose(w);
   static const uint8_t kExpectedContents[] = {
     'R', 'I', 'F', 'F',
@@ -104,9 +113,9 @@
   std::string outfile = webrtc::test::OutputPath() + "wavtest3.wav";
   static const int kSampleRate = 8000;
   static const int kNumChannels = 2;
-  static const int kNumSamples = 3 * kSampleRate * kNumChannels;
+  static const uint32_t kNumSamples = 3 * kSampleRate * kNumChannels;
   float samples[kNumSamples];
-  for (int i = 0; i < kNumSamples; i += kNumChannels) {
+  for (uint32_t i = 0; i < kNumSamples; i += kNumChannels) {
     // A nice periodic beeping sound.
     static const double kToneHz = 440;
     const double t = static_cast<double>(i) / (kNumChannels * kSampleRate);
@@ -117,7 +126,11 @@
   }
   {
     webrtc::WavFile w(outfile, kSampleRate, kNumChannels);
+    EXPECT_EQ(kSampleRate, w.sample_rate());
+    EXPECT_EQ(kNumChannels, w.num_channels());
+    EXPECT_EQ(0u, w.num_samples());
     w.WriteSamples(samples, kNumSamples);
+    EXPECT_EQ(kNumSamples, w.num_samples());
   }
   EXPECT_EQ(sizeof(int16_t) * kNumSamples + webrtc::kWavHeaderSize,
             webrtc::test::GetFileSize(outfile));
diff --git a/webrtc/modules/audio_processing/aec/aec_core.c b/webrtc/modules/audio_processing/aec/aec_core.c
index 37ae621..c194187 100644
--- a/webrtc/modules/audio_processing/aec/aec_core.c
+++ b/webrtc/modules/audio_processing/aec/aec_core.c
@@ -14,6 +14,10 @@
 
 #include "webrtc/modules/audio_processing/aec/aec_core.h"
 
+#ifdef WEBRTC_AEC_DEBUG_DUMP
+#include <stdio.h>
+#endif
+
 #include <assert.h>
 #include <math.h>
 #include <stddef.h>  // size_t
@@ -1054,11 +1058,11 @@
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
   {
-    int16_t farend[PART_LEN];
-    int16_t* farend_ptr = NULL;
+    float farend[PART_LEN];
+    float* 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);
+    rtc_WavWriteSamples(aec->farFile, farend_ptr, PART_LEN);
+    rtc_WavWriteSamples(aec->nearFile, nearend_ptr, PART_LEN);
   }
 #endif
 
@@ -1208,16 +1212,8 @@
   }
 
 #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);
-  }
+  rtc_WavWriteSamples(aec->outLinearFile, e, PART_LEN);
+  rtc_WavWriteSamples(aec->outFile, output, PART_LEN);
 #endif
 }
 
@@ -1272,24 +1268,16 @@
     return -1;
   }
 #ifdef WEBRTC_AEC_DEBUG_DUMP
+  aec->instance_index = webrtc_aec_instance_count;
   aec->far_time_buf =
-      WebRtc_CreateBuffer(kBufSizePartitions, sizeof(int16_t) * PART_LEN);
+      WebRtc_CreateBuffer(kBufSizePartitions, sizeof(float) * 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->farFile = aec->nearFile = aec->outFile = aec->outLinearFile = NULL;
+  aec->debug_dump_count = 0;
 #endif
   aec->delay_estimator_farend =
       WebRtc_CreateDelayEstimatorFarend(PART_LEN1, kHistorySizeBlocks);
@@ -1348,10 +1336,10 @@
   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);
+  rtc_WavClose(aec->farFile);
+  rtc_WavClose(aec->nearFile);
+  rtc_WavClose(aec->outFile);
+  rtc_WavClose(aec->outLinearFile);
 #endif
   WebRtc_FreeDelayEstimator(aec->delay_estimator);
   WebRtc_FreeDelayEstimatorFarend(aec->delay_estimator_farend);
@@ -1360,6 +1348,29 @@
   return 0;
 }
 
+#ifdef WEBRTC_AEC_DEBUG_DUMP
+// Open a new Wav file for writing. If it was already open with a different
+// sample frequency, close it first.
+static void ReopenWav(rtc_WavFile** wav_file,
+                      const char* name,
+                      int seq1,
+                      int seq2,
+                      int sample_rate) {
+  int written UNUSED;
+  char filename[64];
+  if (*wav_file) {
+    if (rtc_WavSampleRate(*wav_file) == sample_rate)
+      return;
+    rtc_WavClose(*wav_file);
+  }
+  written = snprintf(filename, sizeof(filename), "%s%d-%d.wav",
+                     name, seq1, seq2);
+  assert(written >= 0);  // no output error
+  assert((size_t)written < sizeof(filename));  // buffer was large enough
+  *wav_file = rtc_WavOpen(filename, sample_rate, 1);
+}
+#endif  // WEBRTC_AEC_DEBUG_DUMP
+
 int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
   int i;
 
@@ -1400,6 +1411,15 @@
   if (WebRtc_InitBuffer(aec->far_time_buf) == -1) {
     return -1;
   }
+  ReopenWav(&aec->farFile, "aec_far",
+            aec->instance_index, aec->debug_dump_count, sampFreq);
+  ReopenWav(&aec->nearFile, "aec_near",
+            aec->instance_index, aec->debug_dump_count, sampFreq);
+  ReopenWav(&aec->outFile, "aec_out",
+            aec->instance_index, aec->debug_dump_count, sampFreq);
+  ReopenWav(&aec->outLinearFile, "aec_out_linear",
+            aec->instance_index, aec->debug_dump_count, sampFreq);
+  ++aec->debug_dump_count;
 #endif
   aec->system_delay = 0;
 
diff --git a/webrtc/modules/audio_processing/aec/aec_core_internal.h b/webrtc/modules/audio_processing/aec/aec_core_internal.h
index 8e5ee5c..6adc4d6 100644
--- a/webrtc/modules/audio_processing/aec/aec_core_internal.h
+++ b/webrtc/modules/audio_processing/aec/aec_core_internal.h
@@ -11,10 +11,7 @@
 #ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
 #define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
 
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-#include <stdio.h>
-#endif
-
+#include "webrtc/common_audio/wav_writer.h"
 #include "webrtc/modules/audio_processing/aec/aec_common.h"
 #include "webrtc/modules/audio_processing/aec/aec_core.h"
 #include "webrtc/modules/audio_processing/utility/ring_buffer.h"
@@ -141,11 +138,19 @@
   int num_partitions;
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
+  // Sequence number of this AEC instance, so that different instances can
+  // choose different dump file names.
+  int instance_index;
+
+  // Number of times we've restarted dumping; used to pick new dump file names
+  // each time.
+  int debug_dump_count;
+
   RingBuffer* far_time_buf;
-  FILE* farFile;
-  FILE* nearFile;
-  FILE* outFile;
-  FILE* outLinearFile;
+  rtc_WavFile* farFile;
+  rtc_WavFile* nearFile;
+  rtc_WavFile* outFile;
+  rtc_WavFile* outLinearFile;
 #endif
 };
 
diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation.c b/webrtc/modules/audio_processing/aec/echo_cancellation.c
index 7221966..e9e50dc 100644
--- a/webrtc/modules/audio_processing/aec/echo_cancellation.c
+++ b/webrtc/modules/audio_processing/aec/echo_cancellation.c
@@ -158,13 +158,6 @@
   aecpc->lastError = 0;
 
 #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);
@@ -190,7 +183,6 @@
   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);
@@ -281,14 +273,6 @@
     return -1;
   }
 
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-  if (WebRtc_InitBuffer(aecpc->far_pre_buf_s16) == -1) {
-    aecpc->lastError = AEC_UNSPECIFIED_ERROR;
-    return -1;
-  }
-  WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);  // Start overlap.
-#endif
-
   return 0;
 }
 
@@ -332,10 +316,6 @@
   WebRtcAec_SetSystemDelay(aecpc->aec,
                            WebRtcAec_system_delay(aecpc->aec) + newNrOfSamples);
 
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-  WebRtc_WriteBuffer(
-      aecpc->far_pre_buf_s16, farend_ptr, (size_t)newNrOfSamples);
-#endif
   // Write the time-domain data to |far_pre_buf|.
   WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, (size_t)newNrOfSamples);
 
@@ -347,17 +327,14 @@
       float tmp[PART_LEN2];
       WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
       WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
+#ifdef WEBRTC_AEC_DEBUG_DUMP
+      WebRtc_WriteBuffer(
+          WebRtcAec_far_time_buf(aecpc->aec), &ptmp[PART_LEN], 1);
+#endif
     }
 
     // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
     WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
-#ifdef WEBRTC_AEC_DEBUG_DUMP
-    WebRtc_ReadBuffer(
-        aecpc->far_pre_buf_s16, (void**)&farend_ptr, new_farend, PART_LEN2);
-    WebRtc_WriteBuffer(
-        WebRtcAec_far_time_buf(aecpc->aec), &farend_ptr[PART_LEN], 1);
-    WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN);
-#endif
   }
 
   return 0;
diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h b/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h
index e939c42..91f8bab 100644
--- a/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h
+++ b/webrtc/modules/audio_processing/aec/echo_cancellation_internal.h
@@ -42,7 +42,6 @@
   short lastDelayDiff;
 
 #ifdef WEBRTC_AEC_DEBUG_DUMP
-  RingBuffer* far_pre_buf_s16;  // Time domain far-end pre-buffer in int16_t.
   FILE* bufFile;
   FILE* delayFile;
   FILE* skewFile;
diff --git a/webrtc/typedefs.h b/webrtc/typedefs.h
index d8977ff..38cda51 100644
--- a/webrtc/typedefs.h
+++ b/webrtc/typedefs.h
@@ -109,4 +109,15 @@
 #endif
 #endif  // WARN_UNUSED_RESULT
 
+// Put after a variable that might not be used, to prevent compiler warnings:
+//   int result UNUSED = DoSomething();
+//   assert(result == 17);
+#ifndef UNUSED
+#ifdef __GNUC__
+#define UNUSED __attribute__((unused))
+#else
+#define UNUSED
+#endif
+#endif
+
 #endif  // WEBRTC_TYPEDEFS_H_