Skip to content

Commit c70d8ec

Browse files
Implement AudioConstraints.autoGainControl for native platforms (#157)
Additionally: - fix audio preprocessing on native platforms Co-authored-by: evdokimovs <[email protected]>
1 parent 685fe9e commit c70d8ec

File tree

19 files changed

+281
-60
lines changed

19 files changed

+281
-60
lines changed

crates/libwebrtc-sys/include/adm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ class OpenALAudioDeviceModule : public ExtendedADM {
7575

7676
static rtc::scoped_refptr<OpenALAudioDeviceModule> Create(
7777
AudioLayer audio_layer,
78-
webrtc::TaskQueueFactory* task_queue_factory);
78+
webrtc::TaskQueueFactory* task_queue_factory,
79+
webrtc::AudioProcessing* audio_processing);
7980

8081
// Main initialization and termination.
8182
int32_t Init() override;
@@ -216,6 +217,7 @@ class OpenALAudioDeviceModule : public ExtendedADM {
216217
void processRecordingQueued();
217218

218219
std::unique_ptr<webrtc::AudioDeviceBuffer> audio_device_buffer_ = nullptr;
220+
webrtc::AudioProcessing* audio_processing_;
219221

220222
std::recursive_mutex _recording_mutex;
221223
bool _recordingInitialized = false;

crates/libwebrtc-sys/include/audio_device_recorder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ constexpr auto kRecordingPart =
2929
// data to a `bridge::LocalAudioSource`.
3030
class AudioDeviceRecorder {
3131
public:
32-
AudioDeviceRecorder(std::string deviceId);
32+
AudioDeviceRecorder(std::string deviceId, webrtc::AudioProcessing* audio_processing);
3333

3434
// Captures a new batch of audio samples and propagates it to the inner
3535
// `bridge::LocalAudioSource`.
@@ -53,6 +53,7 @@ class AudioDeviceRecorder {
5353
bool validateRecordingDeviceId();
5454

5555
rtc::scoped_refptr<bridge::LocalAudioSource> _source;
56+
webrtc::AudioProcessing* _audio_processing;
5657
ALCdevice* _device;
5758
std::string _deviceId;
5859
std::recursive_mutex _mutex;

crates/libwebrtc-sys/include/bridge.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,15 @@ using RtcpFeedbackMessageType = webrtc::RtcpFeedbackMessageType;
120120
using ScalabilityMode = webrtc::ScalabilityMode;
121121
using RtpCapabilities = webrtc::RtpCapabilities;
122122
using RtpHeaderExtensionCapability = webrtc::RtpHeaderExtensionCapability;
123+
using RuntimeSetting = webrtc::AudioProcessing::RuntimeSetting;
124+
using AudioProcessingConfig = webrtc::AudioProcessing::Config;
123125

124126
// Creates a new proxied `AudioDeviceModule` for the given `AudioLayer`.
125127
std::unique_ptr<AudioDeviceModule> create_audio_device_module(
126128
Thread& worker_thread,
127129
AudioLayer audio_layer,
128-
TaskQueueFactory& task_queue_factory);
130+
TaskQueueFactory& task_queue_factory,
131+
const AudioProcessing& ap);
129132

130133
// Initializes the native audio parts required for each platform.
131134
int32_t init_audio_device_module(const AudioDeviceModule& audio_device_module);
@@ -687,6 +690,23 @@ std::unique_ptr<webrtc::IceCandidateInterface> create_ice_candidate(
687690
rust::Str candidate,
688691
rust::String& error);
689692

693+
// Creates a new `AudioProcessingConfig`.
694+
std::unique_ptr<AudioProcessingConfig> create_audio_processing_config();
695+
696+
// Applies the provided `AudioProcessingConfig` to the provided
697+
// `AudioProcessing`.
698+
void audio_processing_apply_config(const AudioProcessing& ap,
699+
const AudioProcessingConfig& config);
700+
701+
// Returns `AudioProcessingConfig` of the provided `AudioProcessing`.
702+
std::unique_ptr<AudioProcessingConfig> audio_processing_get_config(
703+
const AudioProcessing& ap);
704+
705+
// Enables/disables AGC (auto gain control) in the provided
706+
// `AudioProcessingConfig`.
707+
void config_gain_controller1_set_enabled(AudioProcessingConfig& config,
708+
bool enabled);
709+
690710
} // namespace bridge
691711

692712
#endif // BRIDGE_H_

crates/libwebrtc-sys/include/local_audio_source.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
#include <mutex>
66
#include <optional>
77

8+
#include "api/audio/audio_frame.h"
89
#include "api/audio_options.h"
910
#include "api/media_stream_interface.h"
1011
#include "api/notifier.h"
1112
#include "api/scoped_refptr.h"
13+
#include "modules/audio_processing/include/audio_processing.h"
1214
#include "rust/cxx.h"
1315

1416
namespace bridge {
@@ -21,7 +23,8 @@ class LocalAudioSource : public webrtc::Notifier<webrtc::AudioSourceInterface> {
2123
public:
2224
// Creates a new `LocalAudioSource`.
2325
static rtc::scoped_refptr<LocalAudioSource> Create(
24-
cricket::AudioOptions audio_options);
26+
cricket::AudioOptions audio_options,
27+
std::optional<webrtc::AudioProcessing*> audio_processing);
2528

2629
SourceState state() const override { return kLive; }
2730
bool remote() const override { return false; }
@@ -50,6 +53,8 @@ class LocalAudioSource : public webrtc::Notifier<webrtc::AudioSourceInterface> {
5053
cricket::AudioOptions _options;
5154
std::recursive_mutex sink_lock_;
5255
std::list<webrtc::AudioTrackSinkInterface*> sinks_;
56+
webrtc::AudioFrame audio_frame_;
57+
std::optional<webrtc::AudioProcessing*> audio_processing_;
5358

5459
// Rust side callback that audio level changes are forwarded to.
5560
std::optional<rust::Box<bridge::DynAudioSourceOnAudioLevelChangeCallback>>

crates/libwebrtc-sys/src/bridge.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,7 @@ pub(crate) mod webrtc {
14881488
worker_thread: Pin<&mut Thread>,
14891489
audio_layer: AudioLayer,
14901490
task_queue_factory: Pin<&mut TaskQueueFactory>,
1491+
ap: &AudioProcessing,
14911492
) -> UniquePtr<AudioDeviceModule>;
14921493

14931494
/// Initializes the given [`AudioDeviceModule`].
@@ -1586,6 +1587,7 @@ pub(crate) mod webrtc {
15861587

15871588
unsafe extern "C++" {
15881589
pub type AudioProcessing;
1590+
pub type AudioProcessingConfig;
15891591

15901592
/// Creates a new [`AudioProcessing`].
15911593
pub fn create_audio_processing() -> UniquePtr<AudioProcessing>;
@@ -1597,6 +1599,30 @@ pub(crate) mod webrtc {
15971599
/// will be muted or in some other way not used. This hints the
15981600
/// underlying AGC, AEC, NS processors to halt.
15991601
pub fn set_output_will_be_muted(ap: &AudioProcessing, muted: bool);
1602+
1603+
/// Creates a new [`AudioProcessingConfig`].
1604+
pub fn create_audio_processing_config(
1605+
) -> UniquePtr<AudioProcessingConfig>;
1606+
1607+
/// Returns [`AudioProcessingConfig`] of the provided
1608+
/// [`AudioProcessing`].
1609+
pub fn audio_processing_get_config(
1610+
ap: &AudioProcessing,
1611+
) -> UniquePtr<AudioProcessingConfig>;
1612+
1613+
/// Enables/disables AGC (auto gain control) in the provided
1614+
/// [`AudioProcessingConfig`].
1615+
pub fn config_gain_controller1_set_enabled(
1616+
config: Pin<&mut AudioProcessingConfig>,
1617+
enabled: bool,
1618+
);
1619+
1620+
/// Applies the provided [`AudioProcessingConfig`] to the provided
1621+
/// [`AudioProcessing`].
1622+
pub fn audio_processing_apply_config(
1623+
ap: &AudioProcessing,
1624+
config: &AudioProcessingConfig,
1625+
);
16001626
}
16011627

16021628
unsafe extern "C++" {

crates/libwebrtc-sys/src/cpp/adm.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,11 @@ int32_t OpenALAudioDeviceModule::ActiveAudioLayer(
164164

165165
rtc::scoped_refptr<OpenALAudioDeviceModule> OpenALAudioDeviceModule::Create(
166166
AudioLayer audio_layer,
167-
webrtc::TaskQueueFactory* task_queue_factory) {
167+
webrtc::TaskQueueFactory* task_queue_factory,
168+
webrtc::AudioProcessing* audio_processing) {
168169
auto adm = rtc::make_ref_counted<OpenALAudioDeviceModule>();
169170

171+
adm->audio_processing_ = audio_processing;
170172
adm->audio_device_buffer_ =
171173
std::make_unique<webrtc::AudioDeviceBuffer>(task_queue_factory);
172174

@@ -711,17 +713,17 @@ rtc::scoped_refptr<bridge::LocalAudioSource>
711713
OpenALAudioDeviceModule::CreateAudioSource(uint32_t device_index) {
712714
std::lock_guard<std::recursive_mutex> lk(_recording_mutex);
713715

714-
std::string deviceId;
716+
std::string device_id;
715717
const auto result = DeviceName(ALC_CAPTURE_DEVICE_SPECIFIER, device_index,
716-
nullptr, &deviceId);
718+
nullptr, &device_id);
717719
if (result != 0) {
718720
return nullptr;
719721
}
720722

721-
auto recorder = std::make_unique<AudioDeviceRecorder>(deviceId);
723+
auto recorder = std::make_unique<AudioDeviceRecorder>(device_id, audio_processing_);
722724
recorder->StartCapture();
723725
auto source = recorder->GetSource();
724-
_recorders[deviceId] = std::move(recorder);
726+
_recorders[device_id] = std::move(recorder);
725727
ensureThreadStarted();
726728
startCaptureOnThread();
727729

crates/libwebrtc-sys/src/cpp/audio_device_recorder.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ bool CheckDeviceFailed(ALCdevice* device) {
3434
}
3535
} // namespace recorder
3636

37-
AudioDeviceRecorder::AudioDeviceRecorder(std::string deviceId) {
37+
AudioDeviceRecorder::AudioDeviceRecorder(
38+
std::string deviceId,
39+
webrtc::AudioProcessing* audio_processing) {
3840
_device = alcCaptureOpenDevice(deviceId.empty() ? nullptr : deviceId.c_str(),
3941
kRecordingFrequency, AL_FORMAT_MONO16,
4042
kRecordingFrequency);
41-
_source = bridge::LocalAudioSource::Create(cricket::AudioOptions());
43+
_source = bridge::LocalAudioSource::Create(cricket::AudioOptions(),
44+
audio_processing);
4245
_deviceId = deviceId;
4346
}
4447

crates/libwebrtc-sys/src/cpp/bridge.cc

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,14 @@ std::unique_ptr<VideoTrackSourceInterface> create_device_video_source(
114114
std::unique_ptr<AudioDeviceModule> create_audio_device_module(
115115
Thread& worker_thread,
116116
AudioLayer audio_layer,
117-
TaskQueueFactory& task_queue_factory) {
117+
TaskQueueFactory& task_queue_factory,
118+
const AudioProcessing& ap) {
118119
AudioDeviceModule adm = worker_thread.BlockingCall([audio_layer,
119-
&task_queue_factory] {
120-
return ::OpenALAudioDeviceModule::Create(audio_layer, &task_queue_factory);
120+
&task_queue_factory,
121+
&ap] {
122+
return ::OpenALAudioDeviceModule::Create(audio_layer,
123+
&task_queue_factory,
124+
ap.get());
121125
});
122126

123127
if (adm == nullptr) {
@@ -249,9 +253,14 @@ int32_t set_audio_playout_device(const AudioDeviceModule& audio_device_module,
249253

250254
// Calls `AudioProcessingBuilder().Create()`.
251255
std::unique_ptr<AudioProcessing> create_audio_processing() {
252-
auto ap = webrtc::AudioProcessingBuilder().Create();
256+
webrtc::AudioProcessing::Config apm_config;
257+
apm_config.echo_canceller.enabled = true;
258+
apm_config.echo_canceller.mobile_mode = false;
259+
apm_config.gain_controller1.enabled = true;
260+
apm_config.gain_controller1.enable_limiter = true;
253261

254-
return std::make_unique<AudioProcessing>(ap);
262+
auto apm = webrtc::AudioProcessingBuilder().SetConfig(apm_config).Create();
263+
return std::make_unique<AudioProcessing>(apm);
255264
}
256265

257266
// Calls `AudioProcessing->set_output_will_be_muted()`.
@@ -346,7 +355,7 @@ void dispose_audio_source(const AudioDeviceModule& audio_device_module,
346355
// Creates a new fake `AudioSource`.
347356
std::unique_ptr<AudioSourceInterface> create_fake_audio_source() {
348357
return std::make_unique<AudioSourceInterface>(
349-
bridge::LocalAudioSource::Create(cricket::AudioOptions()));
358+
bridge::LocalAudioSource::Create(cricket::AudioOptions(), nullptr));
350359
}
351360

352361
// Calls `PeerConnectionFactoryInterface->CreateVideoTrack`.
@@ -1161,4 +1170,37 @@ std::unique_ptr<std::string> display_source_title(const DisplaySource& source) {
11611170
return std::make_unique<std::string>(source.title);
11621171
}
11631172

1173+
// Creates a new `AudioProcessingConfig`.
1174+
std::unique_ptr<AudioProcessingConfig> create_audio_processing_config() {
1175+
webrtc::AudioProcessing::Config apm_config;
1176+
apm_config.echo_canceller.enabled = true;
1177+
apm_config.echo_canceller.mobile_mode = false;
1178+
apm_config.gain_controller1.enabled = true;
1179+
apm_config.gain_controller1.mode ==
1180+
webrtc::AudioProcessing::Config::GainController1::kAdaptiveDigital;
1181+
apm_config.gain_controller1.enable_limiter = true;
1182+
return std::make_unique<AudioProcessingConfig>(apm_config);
1183+
}
1184+
1185+
// Enables/disables AGC (auto gain control) in the provided
1186+
// `AudioProcessingConfig`.
1187+
void config_gain_controller1_set_enabled(AudioProcessingConfig& config,
1188+
bool enabled) {
1189+
config.gain_controller1.enabled = enabled;
1190+
config.gain_controller1.analog_gain_controller.enabled = enabled;
1191+
}
1192+
1193+
// Returns `AudioProcessingConfig` of the provided `AudioProcessing`.
1194+
std::unique_ptr<AudioProcessingConfig> audio_processing_get_config(
1195+
const AudioProcessing& ap) {
1196+
return std::make_unique<AudioProcessingConfig>(ap->GetConfig());
1197+
}
1198+
1199+
// Applies the provided `AudioProcessingConfig` to the provided
1200+
// `AudioProcessing`.
1201+
void audio_processing_apply_config(const AudioProcessing& ap,
1202+
const AudioProcessingConfig& config) {
1203+
ap->ApplyConfig(config);
1204+
}
1205+
11641206
} // namespace bridge

crates/libwebrtc-sys/src/cpp/local_audio_source.cc

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ float calculate_audio_level(int16_t* data, int size) {
1414
}
1515

1616
rtc::scoped_refptr<LocalAudioSource> LocalAudioSource::Create(
17-
cricket::AudioOptions audio_options) {
17+
cricket::AudioOptions audio_options,
18+
std::optional<webrtc::AudioProcessing*> audio_processing) {
1819
auto source = rtc::make_ref_counted<LocalAudioSource>();
20+
source->audio_processing_ = audio_processing;
1921
source->_options = audio_options;
2022
return source;
2123
}
@@ -54,8 +56,21 @@ void LocalAudioSource::OnData(const void* audio_data,
5456
}
5557

5658
for (auto* sink : sinks_) {
57-
sink->OnData(audio_data, bits_per_sample, sample_rate, number_of_channels,
58-
number_of_frames);
59+
audio_frame_.UpdateFrame(
60+
0, (const int16_t*)audio_data, sample_rate / 100, sample_rate,
61+
webrtc::AudioFrame::SpeechType::kNormalSpeech,
62+
webrtc::AudioFrame::VADActivity::kVadUnknown, number_of_channels);
63+
if (*audio_processing_) {
64+
webrtc::StreamConfig input_config(sample_rate, number_of_channels);
65+
webrtc::StreamConfig output_config(sample_rate, number_of_channels);
66+
67+
int result =
68+
(*audio_processing_)
69+
->ProcessStream(audio_frame_.data(), input_config, output_config,
70+
audio_frame_.mutable_data());
71+
}
72+
sink->OnData(audio_frame_.data(), bits_per_sample, sample_rate,
73+
number_of_channels, number_of_frames);
5974
}
6075
}
6176

crates/libwebrtc-sys/src/lib.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,15 @@ impl AudioDeviceModule {
217217
worker_thread: &mut Thread,
218218
audio_layer: AudioLayer,
219219
task_queue_factory: &mut TaskQueueFactory,
220+
audio_processing: Option<&AudioProcessing>,
220221
) -> anyhow::Result<Self> {
221222
let ptr = webrtc::create_audio_device_module(
222223
worker_thread.0.pin_mut(),
223224
audio_layer,
224225
task_queue_factory.0.pin_mut(),
226+
&audio_processing
227+
.unwrap_or(&AudioProcessing(UniquePtr::null()))
228+
.0,
225229
);
226230

227231
if ptr.is_null() {
@@ -501,6 +505,23 @@ unsafe impl Sync for webrtc::AudioDeviceModule {}
501505
/// voice processing components designed for real-time communications software.
502506
pub struct AudioProcessing(UniquePtr<webrtc::AudioProcessing>);
503507

508+
/// Representation of an audio processing config.
509+
pub struct AudioProcessingConfig(UniquePtr<webrtc::AudioProcessingConfig>);
510+
511+
impl Default for AudioProcessingConfig {
512+
fn default() -> Self {
513+
Self(webrtc::create_audio_processing_config())
514+
}
515+
}
516+
517+
impl AudioProcessingConfig {
518+
/// Enables/disables AGC (auto gain control) in this
519+
/// [`AudioProcessingConfig`].
520+
pub fn set_gain_controller_enabled(&mut self, enabled: bool) {
521+
webrtc::config_gain_controller1_set_enabled(self.0.pin_mut(), enabled);
522+
}
523+
}
524+
504525
impl AudioProcessing {
505526
/// Creates a new [`AudioProcessing`].
506527
pub fn new() -> anyhow::Result<Self> {
@@ -521,6 +542,18 @@ impl AudioProcessing {
521542
pub fn set_output_will_be_muted(&self, muted: bool) {
522543
webrtc::set_output_will_be_muted(&self.0, muted);
523544
}
545+
546+
/// Returns [`AudioProcessingConfig`] of this [`AudioProcessing`].
547+
#[must_use]
548+
pub fn config(&self) -> AudioProcessingConfig {
549+
AudioProcessingConfig(webrtc::audio_processing_get_config(&self.0))
550+
}
551+
552+
/// Applies the provided [`AudioProcessingConfig`] to this
553+
/// [`AudioProcessing`].
554+
pub fn apply_config(&self, config: &AudioProcessingConfig) {
555+
webrtc::audio_processing_apply_config(&self.0, &config.0);
556+
}
524557
}
525558

526559
unsafe impl Send for webrtc::AudioProcessing {}

0 commit comments

Comments
 (0)