diff --git a/webrtc/common_audio/wav_writer.cc b/webrtc/common_audio/wav_writer.cc index e5714735b..f3b8118c9 100644 --- a/webrtc/common_audio/wav_writer.cc +++ b/webrtc/common_audio/wav_writer.cc @@ -101,3 +101,15 @@ void rtc_WavWriteSamples(rtc_WavFile* wf, size_t num_samples) { reinterpret_cast(wf)->WriteSamples(samples, num_samples); } + +int rtc_WavSampleRate(const rtc_WavFile* wf) { + return reinterpret_cast(wf)->sample_rate(); +} + +int rtc_WavNumChannels(const rtc_WavFile* wf) { + return reinterpret_cast(wf)->num_channels(); +} + +uint32_t rtc_WavNumSamples(const rtc_WavFile* wf) { + return reinterpret_cast(wf)->num_samples(); +} diff --git a/webrtc/common_audio/wav_writer.h b/webrtc/common_audio/wav_writer.h index a8fee51e3..e0582657a 100644 --- a/webrtc/common_audio/wav_writer.h +++ b/webrtc/common_audio/wav_writer.h @@ -34,6 +34,10 @@ class WavFile { // 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_WavClose(rtc_WavFile* wf); 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 9efe96e30..9c593be66 100644 --- a/webrtc/common_audio/wav_writer_unittest.cc +++ b/webrtc/common_audio/wav_writer_unittest.cc @@ -25,10 +25,14 @@ static const float kSamples[] = {0.0, 10.0, 4e4, -1e9}; // 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, CPP) { 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 @@ TEST(WavWriterTest, LargeFile) { 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(i) / (kNumChannels * kSampleRate); @@ -117,7 +126,11 @@ TEST(WavWriterTest, LargeFile) { } { 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 37ae6216e..c194187d2 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 +#endif + #include #include #include // size_t @@ -1054,11 +1058,11 @@ static void ProcessBlock(AecCore* aec) { #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 @@ 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); - } + rtc_WavWriteSamples(aec->outLinearFile, e, PART_LEN); + rtc_WavWriteSamples(aec->outFile, output, PART_LEN); #endif } @@ -1272,24 +1268,16 @@ int WebRtcAec_CreateAec(AecCore** aecInst) { 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 @@ int WebRtcAec_FreeAec(AecCore* aec) { 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 @@ int WebRtcAec_FreeAec(AecCore* aec) { 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 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) { 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 8e5ee5cba..6adc4d68b 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 -#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 @@ struct AecCore { 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 722196656..e9e50dca4 100644 --- a/webrtc/modules/audio_processing/aec/echo_cancellation.c +++ b/webrtc/modules/audio_processing/aec/echo_cancellation.c @@ -158,13 +158,6 @@ int32_t WebRtcAec_Create(void** aecInst) { 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 @@ int32_t WebRtcAec_Free(void* aecInst) { 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 @@ int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) { 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 @@ int32_t WebRtcAec_BufferFarend(void* aecInst, 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 @@ int32_t WebRtcAec_BufferFarend(void* aecInst, 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 e939c4297..91f8bab0f 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 @@ typedef struct { 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 d8977ff4c..38cda513b 100644 --- a/webrtc/typedefs.h +++ b/webrtc/typedefs.h @@ -109,4 +109,15 @@ typedef unsigned __int64 uint64_t; #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_