Skip to content

AVAudioEngine version AudioDeviceModule 2 #177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 82 commits into
base: m125_release
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
b1f993d
Fix missing RTC_OBJC_TYPE macros
hiroshihorie Jun 14, 2024
fd6c13d
Fix missing headers and Metal linking
hiroshihorie Jun 14, 2024
aeef504
Network monitor always enabled
hiroshihorie Jun 14, 2024
8b1c7f3
LK prefixed framework
hiroshihorie Jun 14, 2024
b6d07b8
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Jun 20, 2024
07d9a46
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Jul 9, 2024
d1b814a
Allow to pass in capture session to RTCCameraVideoCapturer
hiroshihorie Jul 13, 2024
634b7d0
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Jul 16, 2024
d05816e
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Aug 13, 2024
67cf254
Prefix RTCDevice category
hiroshihorie Aug 13, 2024
f8f9dc1
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Aug 20, 2024
bd25079
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Sep 17, 2024
00fd89c
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Sep 23, 2024
6902a18
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Sep 23, 2024
7c29b54
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Oct 17, 2024
9742a13
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Oct 19, 2024
f50e159
Merge branch 'm125_release' into livekit-prefixed-m125
hiroshihorie Oct 19, 2024
d29d62c
Remove duplicate RTCCameraVideoCapturer init methods
hiroshihorie Oct 19, 2024
0aca080
Merge branch 'm125_release' into hiroshi/livekit-m125
hiroshihorie Dec 9, 2024
bbe4412
Merge branch 'm125_release' into hiroshi/livekit-m125
hiroshihorie Jan 17, 2025
917c720
Squashed commit of the following:
hiroshihorie Jan 23, 2025
591eb97
Re-wire manual audio input
hiroshihorie Jan 23, 2025
7ece395
bypass & agc
hiroshihorie Jan 24, 2025
536e8ff
Mac aec off by default
hiroshihorie Jan 23, 2025
78c9425
Engine reconfigure
hiroshihorie Jan 25, 2025
261126c
AGC & AEC available
hiroshihorie Jan 26, 2025
d9c7165
Mac device
hiroshihorie Jan 26, 2025
85a0628
Fix build
hiroshihorie Jan 27, 2025
83551f3
Update delegate nullable node for output
hiroshihorie Jan 28, 2025
0397078
Merge branch 'm125_release' into hiroshi/livekit-m125
hiroshihorie Jan 28, 2025
151ac87
Merge branch 'hiroshi/livekit-m125' into hiroshi/livekit-m125-adm-aud…
hiroshihorie Jan 28, 2025
7f0aadb
Start fail workaround
hiroshihorie Jan 28, 2025
2ba3fd6
macos device logic
hiroshihorie Jan 29, 2025
1c01168
Disable apm option manipulation for ios mac
hiroshihorie Jan 29, 2025
fbb0ed7
Fix engine state
hiroshihorie Jan 30, 2025
1460fb4
Catch exception at start
hiroshihorie Jan 30, 2025
0b96f9a
Update io node connection methods
hiroshihorie Feb 3, 2025
1b4bcce
apm mute / unmute
hiroshihorie Feb 7, 2025
2fd53d6
Fix audio frame sample rate when no senders
hiroshihorie Feb 7, 2025
40e7d20
Mute mode
hiroshihorie Feb 8, 2025
4f65581
Simplify logic
hiroshihorie Feb 10, 2025
712009d
Fix state getters
hiroshihorie Feb 8, 2025
d8903c8
is engine running property
hiroshihorie Feb 9, 2025
cbccb5d
is microphone muted property
hiroshihorie Feb 9, 2025
24117ac
Refactor
hiroshihorie Feb 10, 2025
37f9711
Initial unmute for restart mute mode
hiroshihorie Feb 10, 2025
6732a8c
Fix input mixer connection count
hiroshihorie Feb 14, 2025
fa4cddc
set audio device buffer from rtc format
hiroshihorie Feb 14, 2025
e2a567b
Explicit Int16 conversion
hiroshihorie Feb 17, 2025
a890367
set vp enabled property
hiroshihorie Feb 18, 2025
4a5ac4c
Fix device format error crash & return error
hiroshihorie Mar 5, 2025
01f1554
Fix buffer state check
hiroshihorie Mar 5, 2025
b1074f3
propagate error codes
hiroshihorie Mar 5, 2025
0b84894
adm return error code
hiroshihorie Mar 7, 2025
821c91a
Engine state transition
hiroshihorie Mar 8, 2025
9dbf95c
Safe node detach
hiroshihorie Mar 11, 2025
1d91e93
Metal renderer scale patch
hiroshihorie Mar 12, 2025
762d567
setMicrophoneMuted
hiroshihorie Mar 20, 2025
3c0a82e
Merge branch 'hiroshi/livekit-m125-adm-audioengine-fix-stop-crash' in…
hiroshihorie Mar 20, 2025
584715e
Merge branch 'm125_release' into hiroshi/livekit-m125-adm-audioengine
hiroshihorie Mar 20, 2025
e6614c9
Fix state check
hiroshihorie Mar 20, 2025
081cc0f
Revert "Engine state transition"
hiroshihorie Apr 3, 2025
68ef845
Don't mute when removing audio stream
hiroshihorie Mar 25, 2025
adfee74
Simplify pc factory init
hiroshihorie Mar 27, 2025
07ae103
Specify adm type on pc init
hiroshihorie Mar 27, 2025
a940515
Inline input output node check
hiroshihorie Mar 28, 2025
e114436
Unmute on stop recording
hiroshihorie Apr 3, 2025
21ee7f0
input mixer mute mode
hiroshihorie Apr 10, 2025
9f27f86
Move set device logic earlier
hiroshihorie May 2, 2025
fa864f3
Only update state if apply succeeds
hiroshihorie May 2, 2025
6566dd4
Rollback logic
hiroshihorie May 2, 2025
a1bb19a
Move back device config timing
hiroshihorie May 3, 2025
a58a087
macOS device patch 1
hiroshihorie May 15, 2025
212f078
Merge branch 'm125_release' into hiroshi/livekit-m125-adm-audioengine
hiroshihorie May 22, 2025
6a49562
Merge branch 'm125_release' into hiroshi/livekit-m125-adm-audioengine
hiroshihorie Jun 24, 2025
6e5f1c6
Fix logging
hiroshihorie May 23, 2025
daeb79d
Audio device symbols
hiroshihorie May 23, 2025
316d768
Change workaround sleep time to 0.1 sec
hiroshihorie Jun 24, 2025
81a78b6
Merge branch 'm125_release' into hiroshi/livekit-m125-adm-audioengine
hiroshihorie Jun 29, 2025
70272d0
Revert LK prefix
hiroshihorie Jul 1, 2025
09ec011
Fix typo
hiroshihorie Jul 10, 2025
47b4b71
Simplify AudioCustomProcessingAdapter
hiroshihorie Jul 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions audio/audio_send_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,6 @@ void AudioSendStream::SetMuted(bool muted) {
channel_send_->SetInputMute(muted);
}

bool AudioSendStream::GetMuted() {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
return channel_send_->InputMute();
}

webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
return GetStats(true);
}
Expand Down
1 change: 0 additions & 1 deletion audio/audio_send_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ class AudioSendStream final : public webrtc::AudioSendStream,
int payload_frequency,
int event,
int duration_ms) override;
bool GetMuted() override;
void SetMuted(bool muted) override;
webrtc::AudioSendStream::Stats GetStats() const override;
webrtc::AudioSendStream::Stats GetStats(
Expand Down
72 changes: 14 additions & 58 deletions audio/audio_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,22 @@ void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
UpdateAudioTransportWithSendingStreams();

// Make sure recording is initialized; start recording if enabled.
if (ShouldRecord()) {
auto* adm = config_.audio_device_module.get();
if (!adm->Recording()) {
if (adm->InitRecording() == 0) {
if (recording_enabled_) {

// TODO: Verify if the following windows only logic is still required.
auto* adm = config_.audio_device_module.get();
if (!adm->Recording()) {
if (adm->InitRecording() == 0) {
if (recording_enabled_) {
#if defined(WEBRTC_WIN)
if (adm->BuiltInAECIsAvailable() && !adm->Playing()) {
if (!adm->PlayoutIsInitialized()) {
adm->InitPlayout();
}
adm->StartPlayout();
if (adm->BuiltInAECIsAvailable() && !adm->Playing()) {
if (!adm->PlayoutIsInitialized()) {
adm->InitPlayout();
}
#endif
adm->StartRecording();
adm->StartPlayout();
}
} else {
RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
#endif
adm->StartRecording();
}
} else {
RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
}
}
}
Expand All @@ -127,10 +123,7 @@ void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
auto count = sending_streams_.erase(stream);
RTC_DCHECK_EQ(1, count);
UpdateAudioTransportWithSendingStreams();

bool should_record = ShouldRecord();
RTC_LOG(LS_INFO) << "RemoveSendingStream: should_record = " << should_record;
if (!should_record) {
if (sending_streams_.empty()) {
config_.audio_device_module->StopRecording();
}
}
Expand Down Expand Up @@ -158,7 +151,7 @@ void AudioState::SetRecording(bool enabled) {
if (recording_enabled_ != enabled) {
recording_enabled_ = enabled;
if (enabled) {
if (ShouldRecord()) {
if (!sending_streams_.empty()) {
config_.audio_device_module->StartRecording();
}
} else {
Expand Down Expand Up @@ -218,43 +211,6 @@ void AudioState::UpdateNullAudioPollerState() {
null_audio_poller_.Stop();
}
}

void AudioState::OnMuteStreamChanged() {

auto* adm = config_.audio_device_module.get();
bool should_record = ShouldRecord();

RTC_LOG(LS_INFO) << "OnMuteStreamChanged: should_record = " << should_record;
if (should_record && !adm->Recording()) {
if (adm->InitRecording() == 0) {
adm->StartRecording();
}
} else if (!should_record && adm->Recording()) {
adm->StopRecording();
}
}

bool AudioState::ShouldRecord() {
RTC_LOG(LS_INFO) << "ShouldRecord";
// no streams to send
if (sending_streams_.empty()) {
RTC_LOG(LS_INFO) << "ShouldRecord: send stream = empty";
return false;
}

int stream_count = sending_streams_.size();

int muted_count = 0;
for (const auto& kv : sending_streams_) {
if (kv.first->GetMuted()) {
muted_count++;
}
}

RTC_LOG(LS_INFO) << "ShouldRecord: " << muted_count << " muted, " << stream_count << " sending";
return muted_count != stream_count;
}

} // namespace internal

rtc::scoped_refptr<AudioState> AudioState::Create(
Expand Down
5 changes: 0 additions & 5 deletions audio/audio_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ class AudioState : public webrtc::AudioState {

void SetStereoChannelSwapping(bool enable) override;

void OnMuteStreamChanged() override;

AudioDeviceModule* audio_device_module() {
RTC_DCHECK(config_.audio_device_module);
return config_.audio_device_module.get();
Expand All @@ -66,9 +64,6 @@ class AudioState : public webrtc::AudioState {
void UpdateAudioTransportWithSendingStreams();
void UpdateNullAudioPollerState() RTC_RUN_ON(&thread_checker_);

// Returns true when at least 1 stream exists and all streams are not muted.
bool ShouldRecord();

SequenceChecker thread_checker_;
SequenceChecker process_thread_checker_{SequenceChecker::kDetached};
const webrtc::AudioState::Config config_;
Expand Down
4 changes: 2 additions & 2 deletions audio/channel_send.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ class ChannelSend : public ChannelSendInterface,
// Muting, Volume and Level.
void SetInputMute(bool enable) override;

bool InputMute() const override;

// Stats.
ANAStats GetANAStatistics() const override;

Expand Down Expand Up @@ -165,6 +163,8 @@ class ChannelSend : public ChannelSendInterface,
size_t payloadSize,
int64_t absolute_capture_timestamp_ms) override;

bool InputMute() const;

int32_t SendRtpAudio(AudioFrameType frameType,
uint8_t payloadType,
uint32_t rtp_timestamp_without_offset,
Expand Down
2 changes: 0 additions & 2 deletions audio/channel_send.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ class ChannelSendInterface {
virtual bool SendTelephoneEventOutband(int event, int duration_ms) = 0;
virtual void OnBitrateAllocation(BitrateAllocationUpdate update) = 0;
virtual int GetTargetBitrate() const = 0;

virtual bool InputMute() const = 0;
virtual void SetInputMute(bool muted) = 0;

virtual void ProcessAndEncodeAudio(
Expand Down
1 change: 0 additions & 1 deletion call/audio_send_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ class AudioSendStream : public AudioSender {
int event,
int duration_ms) = 0;

virtual bool GetMuted() = 0;
virtual void SetMuted(bool muted) = 0;

virtual Stats GetStats() const = 0;
Expand Down
3 changes: 0 additions & 3 deletions call/audio_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ class AudioState : public rtc::RefCountInterface {

virtual void SetStereoChannelSwapping(bool enable) = 0;

// Notify the AudioState that a stream updated it's mute state.
virtual void OnMuteStreamChanged() = 0;

static rtc::scoped_refptr<AudioState> Create(
const AudioState::Config& config);

Expand Down
87 changes: 45 additions & 42 deletions media/engine/webrtc_voice_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -427,15 +427,10 @@ void WebRtcVoiceEngine::Init() {
// Set default engine options.
{
AudioOptions options;
options.echo_cancellation = true;
options.auto_gain_control = true;
#if defined(WEBRTC_IOS)
// On iOS, VPIO provides built-in NS.
options.echo_cancellation = false;
options.auto_gain_control = false;
options.noise_suppression = false;
#else
options.noise_suppression = true;
#endif
options.highpass_filter = true;
options.highpass_filter = false;
options.stereo_swapping = false;
options.audio_jitter_buffer_max_packets = 200;
options.audio_jitter_buffer_fast_accelerate = false;
Expand Down Expand Up @@ -483,31 +478,14 @@ void WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
// Use desktop AEC by default, when not using hardware AEC.
bool use_mobile_software_aec = false;

#if defined(WEBRTC_IOS) && !TARGET_OS_SIMULATOR
if (options.ios_force_software_aec_HACK &&
*options.ios_force_software_aec_HACK) {
// EC may be forced on for a device known to have non-functioning platform
// AEC.
options.echo_cancellation = true;
RTC_LOG(LS_WARNING)
<< "Force software AEC on iOS. May conflict with platform AEC.";
} else {
// On iOS, VPIO provides built-in EC.
options.echo_cancellation = false;
RTC_LOG(LS_INFO) << "Always disable AEC on iOS. Use built-in instead.";
}
#elif defined(WEBRTC_ANDROID)
use_mobile_software_aec = true;
#endif
// Skip AEC AGC NS option manipulation for iOS adn macOS.
#if !(defined(WEBRTC_IOS) || defined(WEBRTC_MAC))

// Set and adjust gain control options.
#if defined(WEBRTC_IOS) && !TARGET_OS_SIMULATOR
// On iOS, VPIO provides built-in AGC.
options.auto_gain_control = false;
RTC_LOG(LS_INFO) << "Always disable AGC on iOS. Use built-in instead.";
#if defined(WEBRTC_ANDROID)
use_mobile_software_aec = true;
#endif

#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
#if defined(WEBRTC_ANDROID)
// Turn off the gain control if specified by the field trial.
// The purpose of the field trial is to reduce the amount of resampling
// performed inside the audio processing module on mobile platforms by
Expand Down Expand Up @@ -573,6 +551,7 @@ void WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
}
}
}
#endif

if (options.stereo_swapping) {
audio_state()->SetStereoChannelSwapping(*options.stereo_swapping);
Expand Down Expand Up @@ -606,7 +585,7 @@ void WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
if (options.auto_gain_control) {
const bool enabled = *options.auto_gain_control;
apm_config.gain_controller1.enabled = enabled;
#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
#if defined(WEBRTC_IOS) || defined(WEBRTC_MAC) || defined(WEBRTC_ANDROID)
apm_config.gain_controller1.mode =
apm_config.gain_controller1.kFixedDigital;
#else
Expand Down Expand Up @@ -942,7 +921,7 @@ class WebRtcVoiceSendChannel::WebRtcAudioSendStream : public AudioSource::Sink {
muted_ = muted;
}

bool muted() const {
bool IsMuted() const {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
return muted_;
}
Expand All @@ -969,6 +948,11 @@ class WebRtcVoiceSendChannel::WebRtcAudioSendStream : public AudioSource::Sink {
UpdateSendState();
}

bool HasSource() const {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
return source_ != nullptr;
}

// Stops sending by setting the sink of the AudioSource to nullptr. No data
// callback will be received after this method.
// This method is called on the libjingle worker thread.
Expand Down Expand Up @@ -1689,17 +1673,36 @@ bool WebRtcVoiceSendChannel::MuteStream(uint32_t ssrc, bool muted) {
// This implementation is not ideal, instead we should signal the AGC when
// the mic channel is muted/unmuted. We can't do it today because there
// is no good way to know which stream is mapping to the mic channel.
bool all_muted = muted;
for (const auto& kv : send_streams_) {
all_muted = all_muted && kv.second->muted();
}
webrtc::AudioProcessing* ap = engine()->apm();
if (ap) {
ap->set_output_will_be_muted(all_muted);
}
if (send_streams_.size() > 0) {
// This will be true if MuteStream is called from
// AudioRtpSender::ClearSend().
bool is_all_no_source =
std::none_of(send_streams_.begin(), send_streams_.end(),
[](const auto& kv) { return kv.second->HasSource(); });

bool is_all_muted =
std::all_of(send_streams_.begin(), send_streams_.end(),
[](const auto& kv) { return kv.second->IsMuted(); });

// Only mute the microphone if we're not in cleanup state
// (i.e. if we have active send streams)
webrtc::AudioProcessing* ap = engine()->apm();
if (ap) {
bool v = !is_all_no_source && is_all_muted;
RTC_LOG(LS_INFO) << "WebRtcVoiceSendChannel::MuteStream: APM:" << v;
ap->set_output_will_be_muted(v);
}

// Notfy the AudioState that the mute state has updated.
engine_->audio_state()->OnMuteStreamChanged();
if (!is_all_no_source) {
// We don't mute when ClearSend() is called.
webrtc::AudioDeviceModule* adm = engine()->adm();
if (adm) {
RTC_LOG(LS_INFO) << "WebRtcVoiceSendChannel::MuteStream: ADM:"
<< is_all_muted;
adm->SetMicrophoneMute(is_all_muted);
}
}
}

return true;
}
Expand Down
3 changes: 1 addition & 2 deletions media/engine/webrtc_voice_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,6 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface {

absl::optional<webrtc::AudioDeviceModule::Stats> GetAudioDeviceStats()
override;
// Moved to public so WebRtcVoiceMediaChannel can access it.
webrtc::AudioState* audio_state();

private:
// Every option that is "set" will be applied. Every option not "set" will be
Expand All @@ -147,6 +145,7 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface {

webrtc::AudioDeviceModule* adm();
webrtc::AudioProcessing* apm() const;
webrtc::AudioState* audio_state();

std::vector<AudioCodec> CollectCodecs(
const std::vector<webrtc::AudioCodecSpec>& specs) const;
Expand Down
13 changes: 13 additions & 0 deletions modules/audio_device/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -377,12 +377,25 @@ rtc_library("audio_device_impl") {
"linux/pulseaudiosymboltable_linux.h",
]
}
if (is_mac || is_ios) {
sources += [
"audio_engine_device.h",
"audio_engine_device.mm",
]
}
if (is_ios) {
deps += [
"../../sdk:audio_session_objc",
]
}
if (is_mac) {
sources += [
"mac/audio_device_mac.cc",
"mac/audio_device_mac.h",
"mac/audio_mixer_manager_mac.cc",
"mac/audio_mixer_manager_mac.h",
"mac/audio_device_utils_mac.cc",
"mac/audio_device_utils_mac.h",
]
deps += [
":audio_device_impl_frameworks",
Expand Down
10 changes: 10 additions & 0 deletions modules/audio_device/audio_device_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ void AudioDeviceBuffer::StopRecording() {
RTC_LOG(LS_INFO) << "total recording time: " << time_since_start;
}

bool AudioDeviceBuffer::IsPlaying() {
RTC_DCHECK_RUN_ON(&main_thread_checker_);
return playing_;
}

bool AudioDeviceBuffer::IsRecording() {
RTC_DCHECK_RUN_ON(&main_thread_checker_);
return recording_;
}

int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) {
RTC_LOG(LS_INFO) << "SetRecordingSampleRate(" << fsHz << ")";
rec_sample_rate_ = fsHz;
Expand Down
3 changes: 3 additions & 0 deletions modules/audio_device/audio_device_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ class AudioDeviceBuffer {
void StopPlayout();
void StopRecording();

bool IsPlaying();
bool IsRecording();

int32_t SetRecordingSampleRate(uint32_t fsHz);
int32_t SetPlayoutSampleRate(uint32_t fsHz);
uint32_t RecordingSampleRate() const;
Expand Down
Loading