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_