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