From 06013e99ac3f2526784627ca5e0eea78c617db87 Mon Sep 17 00:00:00 2001 From: aleloi Date: Tue, 23 May 2017 08:52:05 -0700 Subject: [PATCH] AecDump implementation. This CL implements webrtc::AecDump, which is an interface defined in https://codereview.webrtc.org/2778783002. This AudioProcessing submodule writes audio and APM state to a file. The file writing is done by posting IO tasks (write_to_file_task.h) on an rtc::TaskQueue. There is an existing implementation for this through AudioProcessing::StartDebugRecording() and AudioProcessing::StopDebugRecording(). This implementation still works, and is used as the default until this dependent CL: https://codereview.webrtc.org/2896813002/. To be able to build webrtc without protobuf support, the interface is isolated from protobuf types. Audio data from AudioProcessing is passed to AecDumpImpl through the AecDump interface. There it is stored in protobuf objects, which are posted on the task queue. This functionality is verified correct by the CL https://codereview.webrtc.org/2864373002, which enables this recording submodule in APM tests. BUG=webrtc:7404 Review-Url: https://codereview.webrtc.org/2865113002 Cr-Commit-Position: refs/heads/master@{#18241} --- webrtc/modules/audio_processing/BUILD.gn | 1 + .../audio_processing/aec_dump/BUILD.gn | 74 +++++++ .../aec_dump/aec_dump_factory.h | 47 ++++ .../aec_dump/aec_dump_impl.cc | 208 ++++++++++++++++++ .../audio_processing/aec_dump/aec_dump_impl.h | 80 +++++++ .../aec_dump/aec_dump_unittest.cc | 71 ++++++ .../aec_dump/capture_stream_info.cc | 69 ++++++ .../aec_dump/capture_stream_info.h | 66 ++++++ .../aec_dump/null_aec_dump_factory.cc | 33 +++ .../aec_dump/write_to_file_task.cc | 68 ++++++ .../aec_dump/write_to_file_task.h | 58 +++++ 11 files changed, 775 insertions(+) create mode 100644 webrtc/modules/audio_processing/aec_dump/BUILD.gn create mode 100644 webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h create mode 100644 webrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc create mode 100644 webrtc/modules/audio_processing/aec_dump/aec_dump_impl.h create mode 100644 webrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc create mode 100644 webrtc/modules/audio_processing/aec_dump/capture_stream_info.cc create mode 100644 webrtc/modules/audio_processing/aec_dump/capture_stream_info.h create mode 100644 webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc create mode 100644 webrtc/modules/audio_processing/aec_dump/write_to_file_task.cc create mode 100644 webrtc/modules/audio_processing/aec_dump/write_to_file_task.h diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn index 86df81da5c..b5209ca458 100644 --- a/webrtc/modules/audio_processing/BUILD.gn +++ b/webrtc/modules/audio_processing/BUILD.gn @@ -494,6 +494,7 @@ if (rtc_include_tests) { ":audioproc_f", ":audioproc_unittest_proto", ":unpack_aecdump", + "aec_dump:aec_dump_unittests", "test/conversational_speech", "test/py_quality_assessment", ] diff --git a/webrtc/modules/audio_processing/aec_dump/BUILD.gn b/webrtc/modules/audio_processing/aec_dump/BUILD.gn new file mode 100644 index 0000000000..4a02299eaa --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/BUILD.gn @@ -0,0 +1,74 @@ +import("../../../webrtc.gni") # This contains def of 'rtc_enable_protobuf' + +rtc_source_set("aec_dump") { + sources = [ + "aec_dump_factory.h", + ] + + public_deps = [ + "..:aec_dump_interface", + ] + + deps = [ + "../../../base:rtc_base_approved", + ] +} + +if (rtc_enable_protobuf) { + rtc_source_set("aec_dump_impl") { + sources = [ + "aec_dump_impl.cc", + "aec_dump_impl.h", + "capture_stream_info.cc", + "capture_stream_info.h", + "write_to_file_task.cc", + "write_to_file_task.h", + ] + + public = [] + + public_deps = [ + ":aec_dump", + "..:aec_dump_interface", + ] + + deps = [ + "../../../base:protobuf_utils", + "../../../base:rtc_base_approved", + "../../../base:rtc_task_queue", + "../../../modules:module_api", + "../../../system_wrappers", + ] + + deps += [ "../:audioproc_debug_proto" ] + } + + rtc_source_set("aec_dump_unittests") { + testonly = true + defines = [] + deps = [ + ":aec_dump_impl", + "..:aec_dump_interface", + "..:audioproc_debug_proto", + "../../../base:rtc_task_queue", + "../../../modules:module_api", + "../../../test:test_support", + "//testing/gtest", + ] + sources = [ + "aec_dump_unittest.cc", + ] + } +} + +rtc_source_set("null_aec_dump_factory") { + assert_no_deps = [ ":aec_dump_impl" ] + sources = [ + "null_aec_dump_factory.cc", + ] + + public_deps = [ + ":aec_dump", + "..:aec_dump_interface", + ] +} diff --git a/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h b/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h new file mode 100644 index 0000000000..98596a4568 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_ + +#include +#include + +#include "webrtc/base/platform_file.h" +#include "webrtc/modules/audio_processing/include/aec_dump.h" + +namespace rtc { +class TaskQueue; +} // namespace rtc + +namespace webrtc { + +class AecDumpFactory { + public: + // The |worker_queue| may not be null and must outlive the created + // AecDump instance. |max_log_size_bytes == -1| means the log size + // will be unlimited. |handle| may not be null. The AecDump takes + // responsibility for |handle| and closes it in the destructor. A + // non-null return value indicates that the file has been + // sucessfully opened. + static std::unique_ptr Create(rtc::PlatformFile file, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue); + static std::unique_ptr Create(std::string file_name, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue); + static std::unique_ptr Create(FILE* handle, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue); +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_FACTORY_H_ diff --git a/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc b/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc new file mode 100644 index 0000000000..256c191539 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "webrtc/modules/audio_processing/aec_dump/aec_dump_impl.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/event.h" +#include "webrtc/base/ptr_util.h" +#include "webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h" + +namespace webrtc { + +namespace { +void CopyFromConfigToEvent(const webrtc::InternalAPMConfig& config, + webrtc::audioproc::Config* pb_cfg) { + pb_cfg->set_aec_enabled(config.aec_enabled); + pb_cfg->set_aec_delay_agnostic_enabled(config.aec_delay_agnostic_enabled); + pb_cfg->set_aec_drift_compensation_enabled( + config.aec_drift_compensation_enabled); + pb_cfg->set_aec_extended_filter_enabled(config.aec_extended_filter_enabled); + pb_cfg->set_aec_suppression_level(config.aec_suppression_level); + + pb_cfg->set_aecm_enabled(config.aecm_enabled); + pb_cfg->set_aecm_comfort_noise_enabled(config.aecm_comfort_noise_enabled); + pb_cfg->set_aecm_routing_mode(config.aecm_routing_mode); + + pb_cfg->set_agc_enabled(config.agc_enabled); + pb_cfg->set_agc_mode(config.agc_mode); + pb_cfg->set_agc_limiter_enabled(config.agc_limiter_enabled); + pb_cfg->set_noise_robust_agc_enabled(config.noise_robust_agc_enabled); + + pb_cfg->set_hpf_enabled(config.hpf_enabled); + + pb_cfg->set_ns_enabled(config.ns_enabled); + pb_cfg->set_ns_level(config.ns_level); + + pb_cfg->set_transient_suppression_enabled( + config.transient_suppression_enabled); + pb_cfg->set_intelligibility_enhancer_enabled( + config.intelligibility_enhancer_enabled); + + pb_cfg->set_experiments_description(config.experiments_description); +} + +} // namespace + +AecDumpImpl::AecDumpImpl(std::unique_ptr debug_file, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) + : debug_file_(std::move(debug_file)), + num_bytes_left_for_log_(max_log_size_bytes), + worker_queue_(worker_queue), + capture_stream_info_(CreateWriteToFileTask()) {} + +AecDumpImpl::~AecDumpImpl() { + // Block until all tasks have finished running. + rtc::Event thread_sync_event(false /* manual_reset */, false); + worker_queue_->PostTask([&thread_sync_event] { thread_sync_event.Set(); }); + // Wait until the event has been signaled with .Set(). By then all + // pending tasks will have finished. + thread_sync_event.Wait(rtc::Event::kForever); +} + +void AecDumpImpl::WriteInitMessage( + const InternalAPMStreamsConfig& streams_config) { + auto task = CreateWriteToFileTask(); + auto* event = task->GetEvent(); + event->set_type(audioproc::Event::INIT); + audioproc::Init* msg = event->mutable_init(); + + msg->set_sample_rate(streams_config.input_sample_rate); + msg->set_output_sample_rate(streams_config.output_sample_rate); + msg->set_reverse_sample_rate(streams_config.render_input_sample_rate); + msg->set_reverse_output_sample_rate(streams_config.render_output_sample_rate); + + msg->set_num_input_channels( + static_cast(streams_config.input_num_channels)); + msg->set_num_output_channels( + static_cast(streams_config.output_num_channels)); + msg->set_num_reverse_channels( + static_cast(streams_config.render_input_num_channels)); + msg->set_num_reverse_output_channels( + streams_config.render_output_num_channels); + + worker_queue_->PostTask(std::unique_ptr(std::move(task))); +} + +void AecDumpImpl::AddCaptureStreamInput(const FloatAudioFrame& src) { + capture_stream_info_.AddInput(src); +} + +void AecDumpImpl::AddCaptureStreamOutput(const FloatAudioFrame& src) { + capture_stream_info_.AddOutput(src); +} + +void AecDumpImpl::AddCaptureStreamInput(const AudioFrame& frame) { + capture_stream_info_.AddInput(frame); +} + +void AecDumpImpl::AddCaptureStreamOutput(const AudioFrame& frame) { + capture_stream_info_.AddOutput(frame); +} + +void AecDumpImpl::AddAudioProcessingState(const AudioProcessingState& state) { + capture_stream_info_.AddAudioProcessingState(state); +} + +void AecDumpImpl::WriteCaptureStreamMessage() { + auto task = capture_stream_info_.GetTask(); + RTC_DCHECK(task); + std::move(task); + worker_queue_->PostTask(std::unique_ptr(std::move(task))); + capture_stream_info_.SetTask(CreateWriteToFileTask()); +} + +void AecDumpImpl::WriteRenderStreamMessage(const AudioFrame& frame) { + auto task = CreateWriteToFileTask(); + auto* event = task->GetEvent(); + + event->set_type(audioproc::Event::REVERSE_STREAM); + audioproc::ReverseStream* msg = event->mutable_reverse_stream(); + const size_t data_size = + sizeof(int16_t) * frame.samples_per_channel_ * frame.num_channels_; + msg->set_data(frame.data_, data_size); + + worker_queue_->PostTask(std::unique_ptr(std::move(task))); +} + +void AecDumpImpl::WriteRenderStreamMessage(const FloatAudioFrame& src) { + auto task = CreateWriteToFileTask(); + auto* event = task->GetEvent(); + + event->set_type(audioproc::Event::REVERSE_STREAM); + + audioproc::ReverseStream* msg = event->mutable_reverse_stream(); + + for (size_t i = 0; i < src.num_channels(); ++i) { + const auto& channel_view = src.channel(i); + msg->add_channel(channel_view.begin(), sizeof(float) * channel_view.size()); + } + + worker_queue_->PostTask(std::unique_ptr(std::move(task))); +} + +void AecDumpImpl::WriteConfig(const InternalAPMConfig& config) { + RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); + auto task = CreateWriteToFileTask(); + auto* event = task->GetEvent(); + event->set_type(audioproc::Event::CONFIG); + CopyFromConfigToEvent(config, event->mutable_config()); + worker_queue_->PostTask(std::unique_ptr(std::move(task))); +} + +std::unique_ptr AecDumpImpl::CreateWriteToFileTask() { + return rtc::MakeUnique(debug_file_.get(), + &num_bytes_left_for_log_); +} + +std::unique_ptr AecDumpFactory::Create(rtc::PlatformFile file, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) { + RTC_DCHECK(worker_queue); + std::unique_ptr debug_file(FileWrapper::Create()); + FILE* handle = rtc::FdopenPlatformFileForWriting(file); + if (!handle) { + return nullptr; + } + if (!debug_file->OpenFromFileHandle(handle)) { + return nullptr; + } + return rtc::MakeUnique(std::move(debug_file), max_log_size_bytes, + worker_queue); +} + +std::unique_ptr AecDumpFactory::Create(std::string file_name, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) { + RTC_DCHECK(worker_queue); + std::unique_ptr debug_file(FileWrapper::Create()); + if (!debug_file->OpenFile(file_name.c_str(), false)) { + return nullptr; + } + return rtc::MakeUnique(std::move(debug_file), max_log_size_bytes, + worker_queue); +} + +std::unique_ptr AecDumpFactory::Create(FILE* handle, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) { + RTC_DCHECK(worker_queue); + RTC_DCHECK(handle); + std::unique_ptr debug_file(FileWrapper::Create()); + if (!debug_file->OpenFromFileHandle(handle)) { + return nullptr; + } + return rtc::MakeUnique(std::move(debug_file), max_log_size_bytes, + worker_queue); +} +} // namespace webrtc diff --git a/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.h b/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.h new file mode 100644 index 0000000000..d9da14b979 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_IMPL_H_ + +#include +#include +#include + +#include "webrtc/base/ignore_wundef.h" +#include "webrtc/base/platform_file.h" +#include "webrtc/base/race_checker.h" +#include "webrtc/base/task_queue.h" +#include "webrtc/base/thread_annotations.h" +#include "webrtc/modules/audio_processing/aec_dump/capture_stream_info.h" +#include "webrtc/modules/audio_processing/aec_dump/write_to_file_task.h" +#include "webrtc/modules/audio_processing/include/aec_dump.h" +#include "webrtc/modules/include/module_common_types.h" +#include "webrtc/system_wrappers/include/file_wrapper.h" + +// Files generated at build-time by the protobuf compiler. +RTC_PUSH_IGNORING_WUNDEF() +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h" +#else +#include "webrtc/modules/audio_processing/debug.pb.h" +#endif +RTC_POP_IGNORING_WUNDEF() + +namespace rtc { +class TaskQueue; +} // namespace rtc + +namespace webrtc { + +// Task-queue based implementation of AecDump. It is thread safe by +// relying on locks in TaskQueue. +class AecDumpImpl : public AecDump { + public: + // Does member variables initialization shared across all c-tors. + AecDumpImpl(std::unique_ptr debug_file, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue); + + ~AecDumpImpl() override; + + void WriteInitMessage(const InternalAPMStreamsConfig& api_format) override; + + void AddCaptureStreamInput(const FloatAudioFrame& src) override; + void AddCaptureStreamOutput(const FloatAudioFrame& src) override; + void AddCaptureStreamInput(const AudioFrame& frame) override; + void AddCaptureStreamOutput(const AudioFrame& frame) override; + void AddAudioProcessingState(const AudioProcessingState& state) override; + void WriteCaptureStreamMessage() override; + + void WriteRenderStreamMessage(const AudioFrame& frame) override; + void WriteRenderStreamMessage(const FloatAudioFrame& src) override; + + void WriteConfig(const InternalAPMConfig& config) override; + + private: + std::unique_ptr CreateWriteToFileTask(); + + std::unique_ptr debug_file_; + int64_t num_bytes_left_for_log_ = 0; + rtc::RaceChecker race_checker_; + rtc::TaskQueue* worker_queue_; + CaptureStreamInfo capture_stream_info_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_AEC_DUMP_IMPL_H_ diff --git a/webrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc b/webrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc new file mode 100644 index 0000000000..3061c23246 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/aec_dump_unittest.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include + +#include "webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h" + +#include "webrtc/base/task_queue.h" +#include "webrtc/modules/include/module_common_types.h" +#include "webrtc/test/gtest.h" +#include "webrtc/test/testsupport/fileutils.h" + +TEST(AecDumper, APICallsDoNotCrash) { + // Note order of initialization: Task queue has to be initialized + // before AecDump. + rtc::TaskQueue file_writer_queue("file_writer_queue"); + + const std::string filename = + webrtc::test::TempFilename(webrtc::test::OutputPath(), "aec_dump"); + + { + std::unique_ptr aec_dump = + webrtc::AecDumpFactory::Create(filename, -1, &file_writer_queue); + + const webrtc::AudioFrame frame; + aec_dump->WriteRenderStreamMessage(frame); + + aec_dump->AddCaptureStreamInput(frame); + aec_dump->AddCaptureStreamOutput(frame); + + aec_dump->WriteCaptureStreamMessage(); + + webrtc::InternalAPMConfig apm_config; + aec_dump->WriteConfig(apm_config); + + webrtc::InternalAPMStreamsConfig streams_config; + aec_dump->WriteInitMessage(streams_config); + } + // Remove file after the AecDump d-tor has finished. + ASSERT_EQ(0, remove(filename.c_str())); +} + +TEST(AecDumper, WriteToFile) { + rtc::TaskQueue file_writer_queue("file_writer_queue"); + + const std::string filename = + webrtc::test::TempFilename(webrtc::test::OutputPath(), "aec_dump"); + + { + std::unique_ptr aec_dump = + webrtc::AecDumpFactory::Create(filename, -1, &file_writer_queue); + const webrtc::AudioFrame frame; + aec_dump->WriteRenderStreamMessage(frame); + } + + // Verify the file has been written after the AecDump d-tor has + // finished. + FILE* fid = fopen(filename.c_str(), "r"); + ASSERT_TRUE(fid != NULL); + + // Clean it up. + ASSERT_EQ(0, fclose(fid)); + ASSERT_EQ(0, remove(filename.c_str())); +} diff --git a/webrtc/modules/audio_processing/aec_dump/capture_stream_info.cc b/webrtc/modules/audio_processing/aec_dump/capture_stream_info.cc new file mode 100644 index 0000000000..2d7affcf4d --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/capture_stream_info.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/audio_processing/aec_dump/capture_stream_info.h" + +namespace webrtc { +CaptureStreamInfo::CaptureStreamInfo(std::unique_ptr task) + : task_(std::move(task)) { + RTC_DCHECK(task_); + task_->GetEvent()->set_type(audioproc::Event::STREAM); +} + +CaptureStreamInfo::~CaptureStreamInfo() = default; + +void CaptureStreamInfo::AddInput(const FloatAudioFrame& src) { + RTC_DCHECK(task_); + auto* stream = task_->GetEvent()->mutable_stream(); + + for (size_t i = 0; i < src.num_channels(); ++i) { + const auto& channel_view = src.channel(i); + stream->add_input_channel(channel_view.begin(), + sizeof(float) * channel_view.size()); + } +} + +void CaptureStreamInfo::AddOutput(const FloatAudioFrame& src) { + RTC_DCHECK(task_); + auto* stream = task_->GetEvent()->mutable_stream(); + + for (size_t i = 0; i < src.num_channels(); ++i) { + const auto& channel_view = src.channel(i); + stream->add_output_channel(channel_view.begin(), + sizeof(float) * channel_view.size()); + } +} + +void CaptureStreamInfo::AddInput(const AudioFrame& frame) { + RTC_DCHECK(task_); + auto* stream = task_->GetEvent()->mutable_stream(); + const size_t data_size = + sizeof(int16_t) * frame.samples_per_channel_ * frame.num_channels_; + stream->set_input_data(frame.data_, data_size); +} + +void CaptureStreamInfo::AddOutput(const AudioFrame& frame) { + RTC_DCHECK(task_); + auto* stream = task_->GetEvent()->mutable_stream(); + const size_t data_size = + sizeof(int16_t) * frame.samples_per_channel_ * frame.num_channels_; + stream->set_output_data(frame.data_, data_size); +} + +void CaptureStreamInfo::AddAudioProcessingState( + const AecDump::AudioProcessingState& state) { + RTC_DCHECK(task_); + auto* stream = task_->GetEvent()->mutable_stream(); + stream->set_delay(state.delay); + stream->set_drift(state.drift); + stream->set_level(state.level); + stream->set_keypress(state.keypress); +} +} // namespace webrtc diff --git a/webrtc/modules/audio_processing/aec_dump/capture_stream_info.h b/webrtc/modules/audio_processing/aec_dump/capture_stream_info.h new file mode 100644 index 0000000000..36b860cea4 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/capture_stream_info.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_CAPTURE_STREAM_INFO_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_CAPTURE_STREAM_INFO_H_ + +#include +#include +#include + +#include "webrtc/base/checks.h" +#include "webrtc/base/ignore_wundef.h" +#include "webrtc/base/logging.h" +#include "webrtc/modules/audio_processing/aec_dump/write_to_file_task.h" +#include "webrtc/modules/audio_processing/include/aec_dump.h" +#include "webrtc/modules/include/module_common_types.h" + +// Files generated at build-time by the protobuf compiler. +RTC_PUSH_IGNORING_WUNDEF() +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h" +#else +#include "webrtc/modules/audio_processing/debug.pb.h" +#endif +RTC_POP_IGNORING_WUNDEF() + +namespace webrtc { + +class CaptureStreamInfo { + public: + explicit CaptureStreamInfo(std::unique_ptr task); + ~CaptureStreamInfo(); + void AddInput(const FloatAudioFrame& src); + void AddOutput(const FloatAudioFrame& src); + + void AddInput(const AudioFrame& frame); + void AddOutput(const AudioFrame& frame); + + void AddAudioProcessingState(const AecDump::AudioProcessingState& state); + + std::unique_ptr GetTask() { + RTC_DCHECK(task_); + return std::move(task_); + } + + void SetTask(std::unique_ptr task) { + RTC_DCHECK(!task_); + RTC_DCHECK(task); + task_ = std::move(task); + task_->GetEvent()->set_type(audioproc::Event::STREAM); + } + + private: + std::unique_ptr task_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_CAPTURE_STREAM_INFO_H_ diff --git a/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc b/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc new file mode 100644 index 0000000000..7da3d5a53b --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/null_aec_dump_factory.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h" +#include "webrtc/modules/audio_processing/include/aec_dump.h" + +namespace webrtc { + +std::unique_ptr AecDumpFactory::Create(rtc::PlatformFile file, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) { + return nullptr; +} + +std::unique_ptr AecDumpFactory::Create(std::string file_name, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) { + return nullptr; +} + +std::unique_ptr AecDumpFactory::Create(FILE* handle, + int64_t max_log_size_bytes, + rtc::TaskQueue* worker_queue) { + return nullptr; +} +} // namespace webrtc diff --git a/webrtc/modules/audio_processing/aec_dump/write_to_file_task.cc b/webrtc/modules/audio_processing/aec_dump/write_to_file_task.cc new file mode 100644 index 0000000000..f9aa567a84 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/write_to_file_task.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/audio_processing/aec_dump/write_to_file_task.h" + +#include "webrtc/base/protobuf_utils.h" + +namespace webrtc { + +WriteToFileTask::WriteToFileTask(webrtc::FileWrapper* debug_file, + int64_t* num_bytes_left_for_log) + : debug_file_(debug_file), + num_bytes_left_for_log_(num_bytes_left_for_log) {} + +WriteToFileTask::~WriteToFileTask() = default; + +audioproc::Event* WriteToFileTask::GetEvent() { + return &event_; +} + +bool WriteToFileTask::IsRoomForNextEvent(size_t event_byte_size) const { + int64_t next_message_size = event_byte_size + sizeof(int32_t); + return (*num_bytes_left_for_log_ < 0) || + (*num_bytes_left_for_log_ >= next_message_size); +} + +void WriteToFileTask::UpdateBytesLeft(size_t event_byte_size) { + RTC_DCHECK(IsRoomForNextEvent(event_byte_size)); + if (*num_bytes_left_for_log_ >= 0) { + *num_bytes_left_for_log_ -= (sizeof(int32_t) + event_byte_size); + } +} + +bool WriteToFileTask::Run() { + if (!debug_file_->is_open()) { + return true; + } + + ProtoString event_string; + event_.SerializeToString(&event_string); + + const size_t event_byte_size = event_.ByteSize(); + + if (!IsRoomForNextEvent(event_byte_size)) { + debug_file_->CloseFile(); + return true; + } + + UpdateBytesLeft(event_byte_size); + + // Write message preceded by its size. + if (!debug_file_->Write(&event_byte_size, sizeof(int32_t))) { + RTC_NOTREACHED(); + } + if (!debug_file_->Write(event_string.data(), event_string.length())) { + RTC_NOTREACHED(); + } + return true; // Delete task from queue at once. +} + +} // namespace webrtc diff --git a/webrtc/modules/audio_processing/aec_dump/write_to_file_task.h b/webrtc/modules/audio_processing/aec_dump/write_to_file_task.h new file mode 100644 index 0000000000..717f645c23 --- /dev/null +++ b/webrtc/modules/audio_processing/aec_dump/write_to_file_task.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_WRITE_TO_FILE_TASK_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_WRITE_TO_FILE_TASK_H_ + +#include +#include +#include + +#include "webrtc/base/checks.h" +#include "webrtc/base/event.h" +#include "webrtc/base/ignore_wundef.h" +#include "webrtc/base/platform_file.h" +#include "webrtc/base/task_queue.h" +#include "webrtc/system_wrappers/include/file_wrapper.h" + +// Files generated at build-time by the protobuf compiler. +RTC_PUSH_IGNORING_WUNDEF() +#ifdef WEBRTC_ANDROID_PLATFORM_BUILD +#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h" +#else +#include "webrtc/modules/audio_processing/debug.pb.h" +#endif +RTC_POP_IGNORING_WUNDEF() + +namespace webrtc { + +class WriteToFileTask : public rtc::QueuedTask { + public: + WriteToFileTask(webrtc::FileWrapper* debug_file, + int64_t* num_bytes_left_for_log); + ~WriteToFileTask() override; + + audioproc::Event* GetEvent(); + + private: + bool IsRoomForNextEvent(size_t event_byte_size) const; + + void UpdateBytesLeft(size_t event_byte_size); + + bool Run() override; + + webrtc::FileWrapper* debug_file_; + audioproc::Event event_; + int64_t* num_bytes_left_for_log_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_DUMP_WRITE_TO_FILE_TASK_H_