aec_dump_impl.cc (11695B)
1 /* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/audio_processing/aec_dump/aec_dump_impl.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <cstdio> 16 #include <memory> 17 #include <string> 18 #include <utility> 19 20 #include "absl/base/nullability.h" 21 #include "absl/strings/string_view.h" 22 #include "api/audio/audio_processing.h" 23 #include "api/audio/audio_view.h" 24 #include "api/task_queue/task_queue_base.h" 25 #include "modules/audio_processing/aec_dump/aec_dump_factory.h" 26 #include "modules/audio_processing/include/aec_dump.h" 27 #include "modules/audio_processing/include/audio_frame_view.h" 28 #include "rtc_base/checks.h" 29 #include "rtc_base/event.h" 30 #include "rtc_base/race_checker.h" 31 #include "rtc_base/system/file_wrapper.h" 32 33 // Generated at build-time by the protobuf compiler. 34 #include "modules/audio_processing/debug.pb.h" 35 36 namespace webrtc { 37 38 namespace { 39 void CopyFromConfigToEvent(const InternalAPMConfig& config, 40 audioproc::Config* pb_cfg) { 41 pb_cfg->set_aec_enabled(config.aec_enabled); 42 pb_cfg->set_aec_delay_agnostic_enabled(config.aec_delay_agnostic_enabled); 43 pb_cfg->set_aec_drift_compensation_enabled( 44 config.aec_drift_compensation_enabled); 45 pb_cfg->set_aec_extended_filter_enabled(config.aec_extended_filter_enabled); 46 pb_cfg->set_aec_suppression_level(config.aec_suppression_level); 47 48 pb_cfg->set_aecm_enabled(config.aecm_enabled); 49 pb_cfg->set_aecm_comfort_noise_enabled(config.aecm_comfort_noise_enabled); 50 pb_cfg->set_aecm_routing_mode(config.aecm_routing_mode); 51 52 pb_cfg->set_agc_enabled(config.agc_enabled); 53 pb_cfg->set_agc_mode(config.agc_mode); 54 pb_cfg->set_agc_limiter_enabled(config.agc_limiter_enabled); 55 pb_cfg->set_noise_robust_agc_enabled(config.noise_robust_agc_enabled); 56 57 pb_cfg->set_hpf_enabled(config.hpf_enabled); 58 59 pb_cfg->set_ns_enabled(config.ns_enabled); 60 pb_cfg->set_ns_level(config.ns_level); 61 62 pb_cfg->set_transient_suppression_enabled( 63 config.transient_suppression_enabled); 64 65 pb_cfg->set_pre_amplifier_enabled(config.pre_amplifier_enabled); 66 pb_cfg->set_pre_amplifier_fixed_gain_factor( 67 config.pre_amplifier_fixed_gain_factor); 68 69 pb_cfg->set_experiments_description(config.experiments_description); 70 } 71 72 } // namespace 73 74 AecDumpImpl::AecDumpImpl(FileWrapper debug_file, 75 int64_t max_log_size_bytes, 76 TaskQueueBase* absl_nonnull worker_queue) 77 : debug_file_(std::move(debug_file)), 78 num_bytes_left_for_log_(max_log_size_bytes), 79 worker_queue_(worker_queue) {} 80 81 AecDumpImpl::~AecDumpImpl() { 82 // Block until all tasks have finished running. 83 Event thread_sync_event; 84 worker_queue_->PostTask([&thread_sync_event] { thread_sync_event.Set(); }); 85 // Wait until the event has been signaled with .Set(). By then all 86 // pending tasks will have finished. 87 thread_sync_event.Wait(Event::kForever); 88 } 89 90 void AecDumpImpl::WriteInitMessage(const ProcessingConfig& api_format, 91 int64_t time_now_ms) { 92 auto event = std::make_unique<audioproc::Event>(); 93 event->set_type(audioproc::Event::INIT); 94 audioproc::Init* msg = event->mutable_init(); 95 96 msg->set_sample_rate(api_format.input_stream().sample_rate_hz()); 97 msg->set_output_sample_rate(api_format.output_stream().sample_rate_hz()); 98 msg->set_reverse_sample_rate( 99 api_format.reverse_input_stream().sample_rate_hz()); 100 msg->set_reverse_output_sample_rate( 101 api_format.reverse_output_stream().sample_rate_hz()); 102 103 msg->set_num_input_channels( 104 static_cast<int32_t>(api_format.input_stream().num_channels())); 105 msg->set_num_output_channels( 106 static_cast<int32_t>(api_format.output_stream().num_channels())); 107 msg->set_num_reverse_channels( 108 static_cast<int32_t>(api_format.reverse_input_stream().num_channels())); 109 msg->set_num_reverse_output_channels( 110 api_format.reverse_output_stream().num_channels()); 111 msg->set_timestamp_ms(time_now_ms); 112 113 PostWriteToFileTask(std::move(event)); 114 } 115 116 void AecDumpImpl::AddCaptureStreamInput( 117 const AudioFrameView<const float>& src) { 118 capture_stream_info_.AddInput(src); 119 } 120 121 void AecDumpImpl::AddCaptureStreamInput(MonoView<const float> channel) { 122 capture_stream_info_.AddInputChannel(channel); 123 } 124 125 void AecDumpImpl::AddCaptureStreamOutput( 126 const AudioFrameView<const float>& src) { 127 capture_stream_info_.AddOutput(src); 128 } 129 130 void AecDumpImpl::AddCaptureStreamOutput(MonoView<const float> channel) { 131 capture_stream_info_.AddOutputChannel(channel); 132 } 133 134 void AecDumpImpl::AddCaptureStreamInput(const int16_t* const data, 135 int num_channels, 136 int samples_per_channel) { 137 capture_stream_info_.AddInput(data, num_channels, samples_per_channel); 138 } 139 140 void AecDumpImpl::AddCaptureStreamOutput(const int16_t* const data, 141 int num_channels, 142 int samples_per_channel) { 143 capture_stream_info_.AddOutput(data, num_channels, samples_per_channel); 144 } 145 146 void AecDumpImpl::AddAudioProcessingState(const AudioProcessingState& state) { 147 capture_stream_info_.AddAudioProcessingState(state); 148 } 149 150 void AecDumpImpl::WriteCaptureStreamMessage() { 151 PostWriteToFileTask(capture_stream_info_.FetchEvent()); 152 } 153 154 void AecDumpImpl::WriteRenderStreamMessage(const int16_t* const data, 155 int num_channels, 156 int samples_per_channel) { 157 auto event = std::make_unique<audioproc::Event>(); 158 event->set_type(audioproc::Event::REVERSE_STREAM); 159 audioproc::ReverseStream* msg = event->mutable_reverse_stream(); 160 const size_t data_size = sizeof(int16_t) * samples_per_channel * num_channels; 161 msg->set_data(data, data_size); 162 163 PostWriteToFileTask(std::move(event)); 164 } 165 166 void AecDumpImpl::WriteRenderStreamMessage( 167 const AudioFrameView<const float>& src) { 168 auto event = std::make_unique<audioproc::Event>(); 169 event->set_type(audioproc::Event::REVERSE_STREAM); 170 171 audioproc::ReverseStream* msg = event->mutable_reverse_stream(); 172 173 for (int i = 0; i < src.num_channels(); ++i) { 174 const auto& channel_view = src.channel(i); 175 msg->add_channel(channel_view.begin(), sizeof(float) * channel_view.size()); 176 } 177 178 PostWriteToFileTask(std::move(event)); 179 } 180 181 void AecDumpImpl::WriteRenderStreamMessage(const float* const* data, 182 int num_channels, 183 int samples_per_channel) { 184 auto event = std::make_unique<audioproc::Event>(); 185 event->set_type(audioproc::Event::REVERSE_STREAM); 186 187 audioproc::ReverseStream* msg = event->mutable_reverse_stream(); 188 189 for (int i = 0; i < num_channels; ++i) { 190 MonoView<const float> channel_view(data[i], samples_per_channel); 191 msg->add_channel(channel_view.begin(), sizeof(float) * channel_view.size()); 192 } 193 194 PostWriteToFileTask(std::move(event)); 195 } 196 197 void AecDumpImpl::WriteConfig(const InternalAPMConfig& config) { 198 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 199 auto event = std::make_unique<audioproc::Event>(); 200 event->set_type(audioproc::Event::CONFIG); 201 CopyFromConfigToEvent(config, event->mutable_config()); 202 PostWriteToFileTask(std::move(event)); 203 } 204 205 void AecDumpImpl::WriteRuntimeSetting( 206 const AudioProcessing::RuntimeSetting& runtime_setting) { 207 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 208 auto event = std::make_unique<audioproc::Event>(); 209 event->set_type(audioproc::Event::RUNTIME_SETTING); 210 audioproc::RuntimeSetting* setting = event->mutable_runtime_setting(); 211 switch (runtime_setting.type()) { 212 case AudioProcessing::RuntimeSetting::Type::kCapturePreGain: { 213 float x; 214 runtime_setting.GetFloat(&x); 215 setting->set_capture_pre_gain(x); 216 break; 217 } 218 case AudioProcessing::RuntimeSetting::Type::kCapturePostGain: { 219 float x; 220 runtime_setting.GetFloat(&x); 221 setting->set_capture_post_gain(x); 222 break; 223 } 224 case AudioProcessing::RuntimeSetting::Type:: 225 kCustomRenderProcessingRuntimeSetting: { 226 float x; 227 runtime_setting.GetFloat(&x); 228 setting->set_custom_render_processing_setting(x); 229 break; 230 } 231 case AudioProcessing::RuntimeSetting::Type::kCaptureCompressionGain: 232 // Runtime AGC1 compression gain is ignored. 233 // TODO(http://bugs.webrtc.org/10432): Store compression gain in aecdumps. 234 break; 235 case AudioProcessing::RuntimeSetting::Type::kCaptureFixedPostGain: { 236 float x; 237 runtime_setting.GetFloat(&x); 238 setting->set_capture_fixed_post_gain(x); 239 break; 240 } 241 case AudioProcessing::RuntimeSetting::Type::kCaptureOutputUsed: { 242 bool x; 243 runtime_setting.GetBool(&x); 244 setting->set_capture_output_used(x); 245 break; 246 } 247 case AudioProcessing::RuntimeSetting::Type::kPlayoutVolumeChange: { 248 int x; 249 runtime_setting.GetInt(&x); 250 setting->set_playout_volume_change(x); 251 break; 252 } 253 case AudioProcessing::RuntimeSetting::Type::kPlayoutAudioDeviceChange: { 254 AudioProcessing::RuntimeSetting::PlayoutAudioDeviceInfo src; 255 runtime_setting.GetPlayoutAudioDeviceInfo(&src); 256 auto* dst = setting->mutable_playout_audio_device_change(); 257 dst->set_id(src.id); 258 dst->set_max_volume(src.max_volume); 259 break; 260 } 261 case AudioProcessing::RuntimeSetting::Type::kNotSpecified: 262 RTC_DCHECK_NOTREACHED(); 263 break; 264 } 265 PostWriteToFileTask(std::move(event)); 266 } 267 268 void AecDumpImpl::PostWriteToFileTask(std::unique_ptr<audioproc::Event> event) { 269 RTC_DCHECK(event); 270 worker_queue_->PostTask([event = std::move(event), this] { 271 std::string event_string = event->SerializeAsString(); 272 const size_t event_byte_size = event_string.size(); 273 274 if (num_bytes_left_for_log_ >= 0) { 275 const int64_t next_message_size = sizeof(int32_t) + event_byte_size; 276 if (num_bytes_left_for_log_ < next_message_size) { 277 // Ensure that no further events are written, even if they're smaller 278 // than the current event. 279 num_bytes_left_for_log_ = 0; 280 return; 281 } 282 num_bytes_left_for_log_ -= next_message_size; 283 } 284 285 // Write message preceded by its size. 286 if (!debug_file_.Write(&event_byte_size, sizeof(int32_t))) { 287 RTC_DCHECK_NOTREACHED(); 288 } 289 if (!debug_file_.Write(event_string.data(), event_string.size())) { 290 RTC_DCHECK_NOTREACHED(); 291 } 292 }); 293 } 294 295 absl_nullable std::unique_ptr<AecDump> AecDumpFactory::Create( 296 FileWrapper file, 297 int64_t max_log_size_bytes, 298 TaskQueueBase* absl_nonnull worker_queue) { 299 RTC_DCHECK(worker_queue); 300 if (!file.is_open()) 301 return nullptr; 302 303 return std::make_unique<AecDumpImpl>(std::move(file), max_log_size_bytes, 304 worker_queue); 305 } 306 307 absl_nullable std::unique_ptr<AecDump> AecDumpFactory::Create( 308 absl::string_view file_name, 309 int64_t max_log_size_bytes, 310 TaskQueueBase* absl_nonnull worker_queue) { 311 return Create(FileWrapper::OpenWriteOnly(file_name), max_log_size_bytes, 312 worker_queue); 313 } 314 315 absl_nullable std::unique_ptr<AecDump> AecDumpFactory::Create( 316 FILE* absl_nonnull handle, 317 int64_t max_log_size_bytes, 318 TaskQueueBase* absl_nonnull worker_queue) { 319 return Create(FileWrapper(handle), max_log_size_bytes, worker_queue); 320 } 321 322 } // namespace webrtc