diff options
author | ivoc <ivoc@webrtc.org> | 2015-12-18 03:53:37 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-18 11:53:42 +0000 |
commit | ae2c5ad12afc8cc29fe9c59dea432b697b871a87 (patch) | |
tree | 1bd755ff0092f04ce5304b980d974b9749ec47fe /webrtc/modules/audio_processing | |
parent | 095ae15d6b9ff60357b44ed6f4997754079eff2e (diff) | |
download | webrtc-ae2c5ad12afc8cc29fe9c59dea432b697b871a87.tar.gz |
Added option to specify a maximum file size when recording an AEC dump.
For applications with a strict filesize limit for debug files,
I added an option to specify a maximum filesize for AEC dumps. An
existing unit test is extended to check that the feature works as
advertised.
BUG=webrtc:4741
TBR=glaznev@webrtc.org
Review URL: https://codereview.webrtc.org/1413483003
Cr-Commit-Position: refs/heads/master@{#11081}
Diffstat (limited to 'webrtc/modules/audio_processing')
7 files changed, 83 insertions, 26 deletions
diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index a332945343..b79b4f0c76 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -632,6 +632,7 @@ int AudioProcessingImpl::ProcessStream(const float* const* src, for (int i = 0; i < formats_.api_format.output_stream().num_channels(); ++i) msg->add_output_channel(dest[i], channel_size); RETURN_ON_ERR(WriteMessageToDebugFile(debug_dump_.debug_file.get(), + &debug_dump_.num_bytes_left_for_log_, &crit_debug_, &debug_dump_.capture)); } #endif @@ -719,6 +720,7 @@ int AudioProcessingImpl::ProcessStream(AudioFrame* frame) { sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_; msg->set_output_data(frame->data_, data_size); RETURN_ON_ERR(WriteMessageToDebugFile(debug_dump_.debug_file.get(), + &debug_dump_.num_bytes_left_for_log_, &crit_debug_, &debug_dump_.capture)); } #endif @@ -886,6 +888,7 @@ int AudioProcessingImpl::AnalyzeReverseStreamLocked( i < formats_.api_format.reverse_input_stream().num_channels(); ++i) msg->add_channel(src[i], channel_size); RETURN_ON_ERR(WriteMessageToDebugFile(debug_dump_.debug_file.get(), + &debug_dump_.num_bytes_left_for_log_, &crit_debug_, &debug_dump_.render)); } #endif @@ -954,6 +957,7 @@ int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) { sizeof(int16_t) * frame->samples_per_channel_ * frame->num_channels_; msg->set_data(frame->data_, data_size); RETURN_ON_ERR(WriteMessageToDebugFile(debug_dump_.debug_file.get(), + &debug_dump_.num_bytes_left_for_log_, &crit_debug_, &debug_dump_.render)); } #endif @@ -1039,7 +1043,8 @@ int AudioProcessingImpl::delay_offset_ms() const { } int AudioProcessingImpl::StartDebugRecording( - const char filename[AudioProcessing::kMaxFilenameSize]) { + const char filename[AudioProcessing::kMaxFilenameSize], + int64_t max_log_size_bytes) { // Run in a single-threaded manner. rtc::CritScope cs_render(&crit_render_); rtc::CritScope cs_capture(&crit_capture_); @@ -1050,6 +1055,7 @@ int AudioProcessingImpl::StartDebugRecording( } #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + debug_dump_.num_bytes_left_for_log_ = max_log_size_bytes; // Stop any ongoing recording. if (debug_dump_.debug_file->Open()) { if (debug_dump_.debug_file->CloseFile() == -1) { @@ -1070,7 +1076,8 @@ int AudioProcessingImpl::StartDebugRecording( #endif // WEBRTC_AUDIOPROC_DEBUG_DUMP } -int AudioProcessingImpl::StartDebugRecording(FILE* handle) { +int AudioProcessingImpl::StartDebugRecording(FILE* handle, + int64_t max_log_size_bytes) { // Run in a single-threaded manner. rtc::CritScope cs_render(&crit_render_); rtc::CritScope cs_capture(&crit_capture_); @@ -1080,6 +1087,8 @@ int AudioProcessingImpl::StartDebugRecording(FILE* handle) { } #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + debug_dump_.num_bytes_left_for_log_ = max_log_size_bytes; + // Stop any ongoing recording. if (debug_dump_.debug_file->Open()) { if (debug_dump_.debug_file->CloseFile() == -1) { @@ -1105,7 +1114,7 @@ int AudioProcessingImpl::StartDebugRecordingForPlatformFile( rtc::CritScope cs_render(&crit_render_); rtc::CritScope cs_capture(&crit_capture_); FILE* stream = rtc::FdopenPlatformFileForWriting(handle); - return StartDebugRecording(stream); + return StartDebugRecording(stream, -1); } int AudioProcessingImpl::StopDebugRecording() { @@ -1400,6 +1409,7 @@ void AudioProcessingImpl::UpdateHistogramsOnCallEnd() { #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP int AudioProcessingImpl::WriteMessageToDebugFile( FileWrapper* debug_file, + int64_t* filesize_limit_bytes, rtc::CriticalSection* crit_debug, ApmDebugDumpThreadState* debug_state) { int32_t size = debug_state->event_msg->ByteSize(); @@ -1417,7 +1427,19 @@ int AudioProcessingImpl::WriteMessageToDebugFile( { // Ensure atomic writes of the message. - rtc::CritScope cs_capture(crit_debug); + rtc::CritScope cs_debug(crit_debug); + + RTC_DCHECK(debug_file->Open()); + // Update the byte counter. + if (*filesize_limit_bytes >= 0) { + *filesize_limit_bytes -= + (sizeof(int32_t) + debug_state->event_str.length()); + if (*filesize_limit_bytes < 0) { + // Not enough bytes are left to write this message, so stop logging. + debug_file->CloseFile(); + return kNoError; + } + } // Write message preceded by its size. if (!debug_file->Write(&size, sizeof(int32_t))) { return kFileError; @@ -1452,6 +1474,7 @@ int AudioProcessingImpl::WriteInitMessage() { // debug_dump_.capture.event_msg. RETURN_ON_ERR(WriteMessageToDebugFile(debug_dump_.debug_file.get(), + &debug_dump_.num_bytes_left_for_log_, &crit_debug_, &debug_dump_.capture)); return kNoError; } @@ -1504,6 +1527,7 @@ int AudioProcessingImpl::WriteConfigMessage(bool forced) { debug_dump_.capture.event_msg->mutable_config()->CopyFrom(config); RETURN_ON_ERR(WriteMessageToDebugFile(debug_dump_.debug_file.get(), + &debug_dump_.num_bytes_left_for_log_, &crit_debug_, &debug_dump_.capture)); return kNoError; } diff --git a/webrtc/modules/audio_processing/audio_processing_impl.h b/webrtc/modules/audio_processing/audio_processing_impl.h index 3506ac4dc0..b720bbf1bc 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.h +++ b/webrtc/modules/audio_processing/audio_processing_impl.h @@ -57,8 +57,9 @@ class AudioProcessingImpl : public AudioProcessing { int Initialize(const ProcessingConfig& processing_config) override; void SetExtraOptions(const Config& config) override; void UpdateHistogramsOnCallEnd() override; - int StartDebugRecording(const char filename[kMaxFilenameSize]) override; - int StartDebugRecording(FILE* handle) override; + int StartDebugRecording(const char filename[kMaxFilenameSize], + int64_t max_log_size_bytes) override; + int StartDebugRecording(FILE* handle, int64_t max_log_size_bytes) override; int StartDebugRecordingForPlatformFile(rtc::PlatformFile handle) override; int StopDebugRecording() override; @@ -143,6 +144,9 @@ class AudioProcessingImpl : public AudioProcessing { struct ApmDebugDumpState { ApmDebugDumpState() : debug_file(FileWrapper::Create()) {} + // Number of bytes that can still be written to the log before the maximum + // size is reached. A value of <= 0 indicates that no limit is used. + int64_t num_bytes_left_for_log_ = -1; rtc::scoped_ptr<FileWrapper> debug_file; ApmDebugDumpThreadState render; ApmDebugDumpThreadState capture; @@ -221,6 +225,7 @@ class AudioProcessingImpl : public AudioProcessing { // TODO(andrew): make this more graceful. Ideally we would split this stuff // out into a separate class with an "enabled" and "disabled" implementation. static int WriteMessageToDebugFile(FileWrapper* debug_file, + int64_t* filesize_limit_bytes, rtc::CriticalSection* crit_debug, ApmDebugDumpThreadState* debug_state); int WriteInitMessage() EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_); diff --git a/webrtc/modules/audio_processing/include/audio_processing.h b/webrtc/modules/audio_processing/include/audio_processing.h index 5fcc4d4672..74ceb4c741 100644 --- a/webrtc/modules/audio_processing/include/audio_processing.h +++ b/webrtc/modules/audio_processing/include/audio_processing.h @@ -408,13 +408,17 @@ class AudioProcessing { // Starts recording debugging information to a file specified by |filename|, // a NULL-terminated string. If there is an ongoing recording, the old file // will be closed, and recording will continue in the newly specified file. - // An already existing file will be overwritten without warning. + // An already existing file will be overwritten without warning. A maximum + // file size (in bytes) for the log can be specified. The logging is stopped + // once the limit has been reached. If max_log_size_bytes is set to a value + // <= 0, no limit will be used. static const size_t kMaxFilenameSize = 1024; - virtual int StartDebugRecording(const char filename[kMaxFilenameSize]) = 0; + virtual int StartDebugRecording(const char filename[kMaxFilenameSize], + int64_t max_log_size_bytes) = 0; // Same as above but uses an existing file handle. Takes ownership // of |handle| and closes it at StopDebugRecording(). - virtual int StartDebugRecording(FILE* handle) = 0; + virtual int StartDebugRecording(FILE* handle, int64_t max_log_size_bytes) = 0; // Same as above but uses an existing PlatformFile handle. Takes ownership // of |handle| and closes it at StopDebugRecording(). diff --git a/webrtc/modules/audio_processing/include/mock_audio_processing.h b/webrtc/modules/audio_processing/include/mock_audio_processing.h index 4ff52baf1c..3aea406bc8 100644 --- a/webrtc/modules/audio_processing/include/mock_audio_processing.h +++ b/webrtc/modules/audio_processing/include/mock_audio_processing.h @@ -250,10 +250,11 @@ class MockAudioProcessing : public AudioProcessing { void(int offset)); MOCK_CONST_METHOD0(delay_offset_ms, int()); - MOCK_METHOD1(StartDebugRecording, - int(const char filename[kMaxFilenameSize])); - MOCK_METHOD1(StartDebugRecording, - int(FILE* handle)); + MOCK_METHOD2(StartDebugRecording, + int(const char filename[kMaxFilenameSize], + int64_t max_log_size_bytes)); + MOCK_METHOD2(StartDebugRecording, + int(FILE* handle, int64_t max_log_size_bytes)); MOCK_METHOD0(StopDebugRecording, int()); MOCK_METHOD0(UpdateHistogramsOnCallEnd, void()); diff --git a/webrtc/modules/audio_processing/test/audio_processing_unittest.cc b/webrtc/modules/audio_processing/test/audio_processing_unittest.cc index eff791d129..b6b94f0fce 100644 --- a/webrtc/modules/audio_processing/test/audio_processing_unittest.cc +++ b/webrtc/modules/audio_processing/test/audio_processing_unittest.cc @@ -388,7 +388,8 @@ class ApmTest : public ::testing::Test { int AnalyzeReverseStreamChooser(Format format); void ProcessDebugDump(const std::string& in_filename, const std::string& out_filename, - Format format); + Format format, + int max_size_bytes); void VerifyDebugDumpTest(Format format); const std::string output_path_; @@ -1711,7 +1712,8 @@ TEST_F(ApmTest, SplittingFilter) { #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP void ApmTest::ProcessDebugDump(const std::string& in_filename, const std::string& out_filename, - Format format) { + Format format, + int max_size_bytes) { FILE* in_file = fopen(in_filename.c_str(), "rb"); ASSERT_TRUE(in_file != NULL); audioproc::Event event_msg; @@ -1739,7 +1741,8 @@ void ApmTest::ProcessDebugDump(const std::string& in_filename, if (first_init) { // StartDebugRecording() writes an additional init message. Don't start // recording until after the first init to avoid the extra message. - EXPECT_NOERR(apm_->StartDebugRecording(out_filename.c_str())); + EXPECT_NOERR( + apm_->StartDebugRecording(out_filename.c_str(), max_size_bytes)); first_init = false; } @@ -1812,34 +1815,54 @@ void ApmTest::VerifyDebugDumpTest(Format format) { test::OutputPath(), std::string("ref") + format_string + "_aecdump"); const std::string out_filename = test::TempFilename( test::OutputPath(), std::string("out") + format_string + "_aecdump"); + const std::string limited_filename = test::TempFilename( + test::OutputPath(), std::string("limited") + format_string + "_aecdump"); + const size_t logging_limit_bytes = 100000; + // We expect at least this many bytes in the created logfile. + const size_t logging_expected_bytes = 95000; EnableAllComponents(); - ProcessDebugDump(in_filename, ref_filename, format); - ProcessDebugDump(ref_filename, out_filename, format); + ProcessDebugDump(in_filename, ref_filename, format, -1); + ProcessDebugDump(ref_filename, out_filename, format, -1); + ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes); FILE* ref_file = fopen(ref_filename.c_str(), "rb"); FILE* out_file = fopen(out_filename.c_str(), "rb"); + FILE* limited_file = fopen(limited_filename.c_str(), "rb"); ASSERT_TRUE(ref_file != NULL); ASSERT_TRUE(out_file != NULL); + ASSERT_TRUE(limited_file != NULL); rtc::scoped_ptr<uint8_t[]> ref_bytes; rtc::scoped_ptr<uint8_t[]> out_bytes; + rtc::scoped_ptr<uint8_t[]> limited_bytes; size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes); size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes); + size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes); size_t bytes_read = 0; + size_t bytes_read_limited = 0; while (ref_size > 0 && out_size > 0) { bytes_read += ref_size; + bytes_read_limited += limited_size; EXPECT_EQ(ref_size, out_size); + EXPECT_GE(ref_size, limited_size); EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size)); + EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size)); ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes); out_size = ReadMessageBytesFromFile(out_file, &out_bytes); + limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes); } EXPECT_GT(bytes_read, 0u); + EXPECT_GT(bytes_read_limited, logging_expected_bytes); + EXPECT_LE(bytes_read_limited, logging_limit_bytes); EXPECT_NE(0, feof(ref_file)); EXPECT_NE(0, feof(out_file)); + EXPECT_NE(0, feof(limited_file)); ASSERT_EQ(0, fclose(ref_file)); ASSERT_EQ(0, fclose(out_file)); + ASSERT_EQ(0, fclose(limited_file)); remove(ref_filename.c_str()); remove(out_filename.c_str()); + remove(limited_filename.c_str()); } TEST_F(ApmTest, VerifyDebugDumpInt) { @@ -1856,13 +1879,13 @@ TEST_F(ApmTest, DebugDump) { const std::string filename = test::TempFilename(test::OutputPath(), "debug_aec"); EXPECT_EQ(apm_->kNullPointerError, - apm_->StartDebugRecording(static_cast<const char*>(NULL))); + apm_->StartDebugRecording(static_cast<const char*>(NULL), -1)); #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP // Stopping without having started should be OK. EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording()); - EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(filename.c_str())); + EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(filename.c_str(), -1)); EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_)); EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording()); @@ -1876,7 +1899,7 @@ TEST_F(ApmTest, DebugDump) { ASSERT_EQ(0, remove(filename.c_str())); #else EXPECT_EQ(apm_->kUnsupportedFunctionError, - apm_->StartDebugRecording(filename.c_str())); + apm_->StartDebugRecording(filename.c_str(), -1)); EXPECT_EQ(apm_->kUnsupportedFunctionError, apm_->StopDebugRecording()); // Verify the file has NOT been written. @@ -1887,7 +1910,7 @@ TEST_F(ApmTest, DebugDump) { // TODO(andrew): expand test to verify output. TEST_F(ApmTest, DebugDumpFromFileHandle) { FILE* fid = NULL; - EXPECT_EQ(apm_->kNullPointerError, apm_->StartDebugRecording(fid)); + EXPECT_EQ(apm_->kNullPointerError, apm_->StartDebugRecording(fid, -1)); const std::string filename = test::TempFilename(test::OutputPath(), "debug_aec"); fid = fopen(filename.c_str(), "w"); @@ -1897,7 +1920,7 @@ TEST_F(ApmTest, DebugDumpFromFileHandle) { // Stopping without having started should be OK. EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording()); - EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(fid)); + EXPECT_EQ(apm_->kNoError, apm_->StartDebugRecording(fid, -1)); EXPECT_EQ(apm_->kNoError, apm_->AnalyzeReverseStream(revframe_)); EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); EXPECT_EQ(apm_->kNoError, apm_->StopDebugRecording()); @@ -1911,7 +1934,7 @@ TEST_F(ApmTest, DebugDumpFromFileHandle) { ASSERT_EQ(0, remove(filename.c_str())); #else EXPECT_EQ(apm_->kUnsupportedFunctionError, - apm_->StartDebugRecording(fid)); + apm_->StartDebugRecording(fid, -1)); EXPECT_EQ(apm_->kUnsupportedFunctionError, apm_->StopDebugRecording()); ASSERT_EQ(0, fclose(fid)); diff --git a/webrtc/modules/audio_processing/test/debug_dump_test.cc b/webrtc/modules/audio_processing/test/debug_dump_test.cc index d2dd9c8b5a..6aa310c088 100644 --- a/webrtc/modules/audio_processing/test/debug_dump_test.cc +++ b/webrtc/modules/audio_processing/test/debug_dump_test.cc @@ -181,7 +181,7 @@ void DebugDumpGenerator::SetOutputChannels(int channels) { } void DebugDumpGenerator::StartRecording() { - apm_->StartDebugRecording(dump_file_name_.c_str()); + apm_->StartDebugRecording(dump_file_name_.c_str(), -1); } void DebugDumpGenerator::Process(size_t num_blocks) { diff --git a/webrtc/modules/audio_processing/test/process_test.cc b/webrtc/modules/audio_processing/test/process_test.cc index ae6b4dc0d5..f54eab3a1e 100644 --- a/webrtc/modules/audio_processing/test/process_test.cc +++ b/webrtc/modules/audio_processing/test/process_test.cc @@ -434,7 +434,7 @@ void void_main(int argc, char* argv[]) { } else if (strcmp(argv[i], "--debug_file") == 0) { i++; ASSERT_LT(i, argc) << "Specify filename after --debug_file"; - ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i])); + ASSERT_EQ(apm->kNoError, apm->StartDebugRecording(argv[i], -1)); } else { FAIL() << "Unrecognized argument " << argv[i]; } |