Chromium Code Reviews| Index: webrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc |
| 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 0000000000000000000000000000000000000000..dbcbead56125fce7112504138cd1367a3bb367be |
| --- /dev/null |
| +++ b/webrtc/modules/audio_processing/aec_dump/aec_dump_impl.cc |
| @@ -0,0 +1,257 @@ |
| +/* |
| + * 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 <utility> |
| + |
| +#include "webrtc/modules/audio_processing/aec_dump/aec_dump_impl.h" |
| + |
| +#include "webrtc/base/checks.h" |
| +#include "webrtc/base/event.h" |
| +#include "webrtc/modules/audio_processing/aec_dump/aec_dump_factory.h" |
| + |
| +namespace webrtc { |
| + |
| +class WriteToFileTask : public rtc::QueuedTask { |
| + public: |
| + WriteToFileTask(webrtc::FileWrapper* debug_file, |
| + std::unique_ptr<audioproc::Event> event, |
| + int64_t* num_bytes_left_for_log) |
| + : debug_file_(debug_file), |
| + event_(std::move(event)), |
| + num_bytes_left_for_log_(num_bytes_left_for_log) {} |
| + |
| + private: |
| + bool 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 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 Run() override { |
| + if (!debug_file_->is_open()) { |
| + return true; |
| + } |
| + |
| + std::string 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. TODO(aleloi): |
| + // instead consider a 'mega-task' that returns |
| + // 'false', checks if there is something in a |
| + // swap-queue and reposts itself periodically. |
| + } |
| + |
| + webrtc::FileWrapper* debug_file_; |
| + std::unique_ptr<audioproc::Event> event_; |
| + int64_t* num_bytes_left_for_log_; |
| +}; |
| + |
| +AecDumpImpl::AecDumpImpl(int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) |
| + : debug_file_(FileWrapper::Create()), |
| + num_bytes_left_for_log_(max_log_size_bytes), |
| + worker_queue_(worker_queue) {} |
| + |
| +AecDumpImpl::AecDumpImpl(rtc::PlatformFile file, |
| + int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) |
| + : AecDumpImpl(max_log_size_bytes, worker_queue) { |
| + FILE* handle = rtc::FdopenPlatformFileForWriting(file); |
| + RTC_DCHECK(handle); |
| + debug_file_->OpenFromFileHandle(handle); |
| +} |
| + |
| +AecDumpImpl::AecDumpImpl(std::string file_name, |
| + int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) |
| + : AecDumpImpl(max_log_size_bytes, worker_queue) { |
| + RTC_DCHECK(debug_file_); |
| + debug_file_->OpenFile(file_name.c_str(), false); |
| +} |
| + |
| +AecDumpImpl::AecDumpImpl(FILE* handle, |
| + int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) |
| + : AecDumpImpl(max_log_size_bytes, worker_queue) { |
| + RTC_DCHECK(debug_file_); |
| + debug_file_->OpenFromFileHandle(handle); |
| +} |
| + |
| +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(); }); |
| + thread_sync_event.Wait(rtc::Event::kForever); |
| +} |
| + |
| +std::unique_ptr<AecDump::CaptureStreamInfo> AecDumpImpl::GetCaptureStreamInfo() |
| + const { |
| + return std::unique_ptr<CaptureStreamInfoImpl>(new CaptureStreamInfoImpl( |
| + std::unique_ptr<audioproc::Event>(new audioproc::Event()))); |
| +} |
| + |
| +void AecDumpImpl::WriteInitMessage( |
| + const InternalAPMStreamsConfig& streams_config) { |
| + auto event = std::unique_ptr<audioproc::Event>(new audioproc::Event()); |
| + 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<int32_t>(streams_config.input_num_channels)); |
| + msg->set_num_output_channels( |
| + static_cast<int32_t>(streams_config.output_num_channels)); |
| + msg->set_num_reverse_channels( |
| + static_cast<int32_t>(streams_config.render_input_num_channels)); |
| + msg->set_num_reverse_output_channels( |
| + streams_config.render_output_num_channels); |
| + |
| + PostTask(std::move(event)); |
| +} |
| + |
| +void AecDumpImpl::WriteRenderStreamMessage(const AudioFrame& frame) { |
| + auto event = std::unique_ptr<audioproc::Event>(new audioproc::Event()); |
| + |
| + 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); |
| + |
| + PostTask(std::move(event)); |
| +} |
| + |
| +void AecDumpImpl::WriteRenderStreamMessage(FloatAudioFrame src) { |
| + auto event = std::unique_ptr<audioproc::Event>(new audioproc::Event()); |
| + 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()); |
| + } |
| + |
| + PostTask(std::move(event)); |
| +} |
| + |
| +void AecDumpImpl::WriteCaptureStreamMessage( |
| + std::unique_ptr<CaptureStreamInfo> capture_stream_info) { |
| + // Really ugly, how is it done better? |
| + auto event_ptr = |
| + static_cast<CaptureStreamInfoImpl*>(capture_stream_info.get()) |
| + ->GetEventMsg(); |
| + if (event_ptr) { |
| + PostTask(std::move(event_ptr)); |
| + } |
| +} |
| + |
| +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); |
| +} |
| + |
| +void AecDumpImpl::WriteConfig(const InternalAPMConfig& config, bool forced) { |
| + auto event = std::unique_ptr<audioproc::Event>(new audioproc::Event()); |
|
peah-webrtc
2017/05/04 14:40:32
Is it possible to have event being a part of Write
|
| + event->set_type(audioproc::Event::CONFIG); |
| + CopyFromConfigToEvent(config, event->mutable_config()); |
| + |
| + ProtoString serialized_config = event->mutable_config()->SerializeAsString(); |
| + { |
| + rtc::CritScope cs(&config_string_lock_); |
| + if (!forced && serialized_config == last_serialized_capture_config_) { |
| + return; |
| + } |
| + last_serialized_capture_config_ = serialized_config; |
| + } |
| + |
| + PostTask(std::move(event)); |
| +} |
| + |
| +void AecDumpImpl::PostTask(std::unique_ptr<audioproc::Event> event) { |
| + RTC_DCHECK(event); |
| + worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(new WriteToFileTask( |
|
peah-webrtc
2017/05/04 14:40:32
Is it needed to create a new task here? Can't we r
|
| + debug_file_.get(), std::move(event), &num_bytes_left_for_log_))); |
| +} |
| + |
| +std::unique_ptr<AecDump> AecDumpFactory::Create(rtc::PlatformFile file, |
| + int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) { |
| + return std::unique_ptr<AecDumpImpl>( |
| + new AecDumpImpl(file, max_log_size_bytes, worker_queue)); |
| +} |
| + |
| +std::unique_ptr<AecDump> AecDumpFactory::Create(std::string file_name, |
| + int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) { |
| + return std::unique_ptr<AecDumpImpl>( |
| + new AecDumpImpl(file_name, max_log_size_bytes, worker_queue)); |
| +} |
| + |
| +std::unique_ptr<AecDump> AecDumpFactory::Create(FILE* handle, |
| + int64_t max_log_size_bytes, |
| + rtc::TaskQueue* worker_queue) { |
| + return std::unique_ptr<AecDumpImpl>( |
| + new AecDumpImpl(handle, max_log_size_bytes, worker_queue)); |
| +} |
| +} // namespace webrtc |