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 "modules/audio_processing/aec_dump/aec_dump_factory.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/event.h"
19
20 namespace webrtc {
21
22 namespace {
CopyFromConfigToEvent(const webrtc::InternalAPMConfig & config,webrtc::audioproc::Config * pb_cfg)23 void CopyFromConfigToEvent(const webrtc::InternalAPMConfig& config,
24 webrtc::audioproc::Config* pb_cfg) {
25 pb_cfg->set_aec_enabled(config.aec_enabled);
26 pb_cfg->set_aec_delay_agnostic_enabled(config.aec_delay_agnostic_enabled);
27 pb_cfg->set_aec_drift_compensation_enabled(
28 config.aec_drift_compensation_enabled);
29 pb_cfg->set_aec_extended_filter_enabled(config.aec_extended_filter_enabled);
30 pb_cfg->set_aec_suppression_level(config.aec_suppression_level);
31
32 pb_cfg->set_aecm_enabled(config.aecm_enabled);
33 pb_cfg->set_aecm_comfort_noise_enabled(config.aecm_comfort_noise_enabled);
34 pb_cfg->set_aecm_routing_mode(config.aecm_routing_mode);
35
36 pb_cfg->set_agc_enabled(config.agc_enabled);
37 pb_cfg->set_agc_mode(config.agc_mode);
38 pb_cfg->set_agc_limiter_enabled(config.agc_limiter_enabled);
39 pb_cfg->set_noise_robust_agc_enabled(config.noise_robust_agc_enabled);
40
41 pb_cfg->set_hpf_enabled(config.hpf_enabled);
42
43 pb_cfg->set_ns_enabled(config.ns_enabled);
44 pb_cfg->set_ns_level(config.ns_level);
45
46 pb_cfg->set_transient_suppression_enabled(
47 config.transient_suppression_enabled);
48
49 pb_cfg->set_pre_amplifier_enabled(config.pre_amplifier_enabled);
50 pb_cfg->set_pre_amplifier_fixed_gain_factor(
51 config.pre_amplifier_fixed_gain_factor);
52
53 pb_cfg->set_experiments_description(config.experiments_description);
54 }
55
56 } // namespace
57
AecDumpImpl(FileWrapper debug_file,int64_t max_log_size_bytes,rtc::TaskQueue * worker_queue)58 AecDumpImpl::AecDumpImpl(FileWrapper debug_file,
59 int64_t max_log_size_bytes,
60 rtc::TaskQueue* worker_queue)
61 : debug_file_(std::move(debug_file)),
62 num_bytes_left_for_log_(max_log_size_bytes),
63 worker_queue_(worker_queue),
64 capture_stream_info_(CreateWriteToFileTask()) {}
65
~AecDumpImpl()66 AecDumpImpl::~AecDumpImpl() {
67 // Block until all tasks have finished running.
68 rtc::Event thread_sync_event;
69 worker_queue_->PostTask([&thread_sync_event] { thread_sync_event.Set(); });
70 // Wait until the event has been signaled with .Set(). By then all
71 // pending tasks will have finished.
72 thread_sync_event.Wait(rtc::Event::kForever);
73 }
74
WriteInitMessage(const ProcessingConfig & api_format,int64_t time_now_ms)75 void AecDumpImpl::WriteInitMessage(const ProcessingConfig& api_format,
76 int64_t time_now_ms) {
77 auto task = CreateWriteToFileTask();
78 auto* event = task->GetEvent();
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 worker_queue_->PostTask(std::move(task));
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 auto task = capture_stream_info_.GetTask();
130 RTC_DCHECK(task);
131 worker_queue_->PostTask(std::move(task));
132 capture_stream_info_.SetTask(CreateWriteToFileTask());
133 }
134
WriteRenderStreamMessage(const int16_t * const data,int num_channels,int samples_per_channel)135 void AecDumpImpl::WriteRenderStreamMessage(const int16_t* const data,
136 int num_channels,
137 int samples_per_channel) {
138 auto task = CreateWriteToFileTask();
139 auto* event = task->GetEvent();
140
141 event->set_type(audioproc::Event::REVERSE_STREAM);
142 audioproc::ReverseStream* msg = event->mutable_reverse_stream();
143 const size_t data_size = sizeof(int16_t) * samples_per_channel * num_channels;
144 msg->set_data(data, data_size);
145
146 worker_queue_->PostTask(std::move(task));
147 }
148
WriteRenderStreamMessage(const AudioFrameView<const float> & src)149 void AecDumpImpl::WriteRenderStreamMessage(
150 const AudioFrameView<const float>& src) {
151 auto task = CreateWriteToFileTask();
152 auto* event = task->GetEvent();
153
154 event->set_type(audioproc::Event::REVERSE_STREAM);
155
156 audioproc::ReverseStream* msg = event->mutable_reverse_stream();
157
158 for (size_t i = 0; i < src.num_channels(); ++i) {
159 const auto& channel_view = src.channel(i);
160 msg->add_channel(channel_view.begin(), sizeof(float) * channel_view.size());
161 }
162
163 worker_queue_->PostTask(std::move(task));
164 }
165
WriteConfig(const InternalAPMConfig & config)166 void AecDumpImpl::WriteConfig(const InternalAPMConfig& config) {
167 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
168 auto task = CreateWriteToFileTask();
169 auto* event = task->GetEvent();
170 event->set_type(audioproc::Event::CONFIG);
171 CopyFromConfigToEvent(config, event->mutable_config());
172 worker_queue_->PostTask(std::move(task));
173 }
174
WriteRuntimeSetting(const AudioProcessing::RuntimeSetting & runtime_setting)175 void AecDumpImpl::WriteRuntimeSetting(
176 const AudioProcessing::RuntimeSetting& runtime_setting) {
177 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
178 auto task = CreateWriteToFileTask();
179 auto* event = task->GetEvent();
180 event->set_type(audioproc::Event::RUNTIME_SETTING);
181 audioproc::RuntimeSetting* setting = event->mutable_runtime_setting();
182 switch (runtime_setting.type()) {
183 case AudioProcessing::RuntimeSetting::Type::kCapturePreGain: {
184 float x;
185 runtime_setting.GetFloat(&x);
186 setting->set_capture_pre_gain(x);
187 break;
188 }
189 case AudioProcessing::RuntimeSetting::Type::
190 kCustomRenderProcessingRuntimeSetting: {
191 float x;
192 runtime_setting.GetFloat(&x);
193 setting->set_custom_render_processing_setting(x);
194 break;
195 }
196 case AudioProcessing::RuntimeSetting::Type::kCaptureCompressionGain:
197 // Runtime AGC1 compression gain is ignored.
198 // TODO(http://bugs.webrtc.org/10432): Store compression gain in aecdumps.
199 break;
200 case AudioProcessing::RuntimeSetting::Type::kCaptureFixedPostGain: {
201 float x;
202 runtime_setting.GetFloat(&x);
203 setting->set_capture_fixed_post_gain(x);
204 break;
205 }
206 case AudioProcessing::RuntimeSetting::Type::kPlayoutVolumeChange: {
207 int x;
208 runtime_setting.GetInt(&x);
209 setting->set_playout_volume_change(x);
210 break;
211 }
212 case AudioProcessing::RuntimeSetting::Type::kPlayoutAudioDeviceChange: {
213 AudioProcessing::RuntimeSetting::PlayoutAudioDeviceInfo src;
214 runtime_setting.GetPlayoutAudioDeviceInfo(&src);
215 auto* dst = setting->mutable_playout_audio_device_change();
216 dst->set_id(src.id);
217 dst->set_max_volume(src.max_volume);
218 break;
219 }
220 case AudioProcessing::RuntimeSetting::Type::kNotSpecified:
221 RTC_NOTREACHED();
222 break;
223 }
224 worker_queue_->PostTask(std::move(task));
225 }
226
CreateWriteToFileTask()227 std::unique_ptr<WriteToFileTask> AecDumpImpl::CreateWriteToFileTask() {
228 return std::make_unique<WriteToFileTask>(&debug_file_,
229 &num_bytes_left_for_log_);
230 }
231
Create(webrtc::FileWrapper file,int64_t max_log_size_bytes,rtc::TaskQueue * worker_queue)232 std::unique_ptr<AecDump> AecDumpFactory::Create(webrtc::FileWrapper file,
233 int64_t max_log_size_bytes,
234 rtc::TaskQueue* worker_queue) {
235 RTC_DCHECK(worker_queue);
236 if (!file.is_open())
237 return nullptr;
238
239 return std::make_unique<AecDumpImpl>(std::move(file), max_log_size_bytes,
240 worker_queue);
241 }
242
Create(std::string file_name,int64_t max_log_size_bytes,rtc::TaskQueue * worker_queue)243 std::unique_ptr<AecDump> AecDumpFactory::Create(std::string file_name,
244 int64_t max_log_size_bytes,
245 rtc::TaskQueue* worker_queue) {
246 return Create(FileWrapper::OpenWriteOnly(file_name.c_str()),
247 max_log_size_bytes, worker_queue);
248 }
249
Create(FILE * handle,int64_t max_log_size_bytes,rtc::TaskQueue * worker_queue)250 std::unique_ptr<AecDump> AecDumpFactory::Create(FILE* handle,
251 int64_t max_log_size_bytes,
252 rtc::TaskQueue* worker_queue) {
253 return Create(FileWrapper(handle), max_log_size_bytes, worker_queue);
254 }
255
256 } // namespace webrtc
257