Skip to content

Commit 272127d

Browse files
cloudwebrtchiroshihoriedavidzhao
committed
Audio Device Optimization
allow listen-only mode in AudioUnit, adjust when category changes (#2) release mic when category changes (#5) Change defaults to iOS defaults (#7) Sync audio session config (#8) feat: support bypass voice processing for iOS. (#15) Remove MacBookPro audio pan right code (#22) fix: Fix can't open mic alone when built-in AEC is enabled. (#29) feat: add audio device changes detect for windows. (#41) fix Linux compile (#47) AudioUnit: Don't rely on category switch for mic indicator to turn off (#52) Stop recording on mute (turn off mic indicator) (#55) Cherry pick audio selection from m97 release (#35) [Mac] Allow audio device selection (#21) RTCAudioDeviceModule.outputDevice / inputDevice getter and setter (#80) Co-authored-by: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Co-authored-by: David Zhao <dz@livekit.io>
1 parent 3cccc9f commit 272127d

40 files changed

+1187
-203
lines changed

audio/audio_send_stream.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ void AudioSendStream::SetMuted(bool muted) {
424424
channel_send_->SetInputMute(muted);
425425
}
426426

427+
bool AudioSendStream::GetMuted() {
428+
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
429+
return channel_send_->InputMute();
430+
}
431+
427432
webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
428433
return GetStats(true);
429434
}

audio/audio_send_stream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class AudioSendStream final : public webrtc::AudioSendStream,
9696
int payload_frequency,
9797
int event,
9898
int duration_ms) override;
99+
bool GetMuted() override;
99100
void SetMuted(bool muted) override;
100101
webrtc::AudioSendStream::Stats GetStats() const override;
101102
webrtc::AudioSendStream::Stats GetStats(

audio/audio_state.cc

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,26 @@ void AudioState::AddSendingStream(webrtc::AudioSendStream* stream,
9898
UpdateAudioTransportWithSendingStreams();
9999

100100
// Make sure recording is initialized; start recording if enabled.
101-
auto* adm = config_.audio_device_module.get();
102-
if (!adm->Recording()) {
103-
if (adm->InitRecording() == 0) {
104-
if (recording_enabled_) {
105-
adm->StartRecording();
101+
if (ShouldRecord()) {
102+
auto* adm = config_.audio_device_module.get();
103+
if (!adm->Recording()) {
104+
if (adm->InitRecording() == 0) {
105+
if (recording_enabled_) {
106+
107+
// TODO: Verify if the following windows only logic is still required.
108+
#if defined(WEBRTC_WIN)
109+
if (adm->BuiltInAECIsAvailable() && !adm->Playing()) {
110+
if (!adm->PlayoutIsInitialized()) {
111+
adm->InitPlayout();
112+
}
113+
adm->StartPlayout();
114+
}
115+
#endif
116+
adm->StartRecording();
117+
}
118+
} else {
119+
RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
106120
}
107-
} else {
108-
RTC_DLOG_F(LS_ERROR) << "Failed to initialize recording.";
109121
}
110122
}
111123
}
@@ -115,7 +127,8 @@ void AudioState::RemoveSendingStream(webrtc::AudioSendStream* stream) {
115127
auto count = sending_streams_.erase(stream);
116128
RTC_DCHECK_EQ(1, count);
117129
UpdateAudioTransportWithSendingStreams();
118-
if (sending_streams_.empty()) {
130+
131+
if (!ShouldRecord()) {
119132
config_.audio_device_module->StopRecording();
120133
}
121134
}
@@ -143,7 +156,7 @@ void AudioState::SetRecording(bool enabled) {
143156
if (recording_enabled_ != enabled) {
144157
recording_enabled_ = enabled;
145158
if (enabled) {
146-
if (!sending_streams_.empty()) {
159+
if (ShouldRecord()) {
147160
config_.audio_device_module->StartRecording();
148161
}
149162
} else {
@@ -203,6 +216,39 @@ void AudioState::UpdateNullAudioPollerState() {
203216
null_audio_poller_.Stop();
204217
}
205218
}
219+
220+
void AudioState::OnMuteStreamChanged() {
221+
222+
auto* adm = config_.audio_device_module.get();
223+
bool should_record = ShouldRecord();
224+
225+
if (should_record && !adm->Recording()) {
226+
if (adm->InitRecording() == 0) {
227+
adm->StartRecording();
228+
}
229+
} else if (!should_record && adm->Recording()) {
230+
adm->StopRecording();
231+
}
232+
}
233+
234+
bool AudioState::ShouldRecord() {
235+
// no streams to send
236+
if (sending_streams_.empty()) {
237+
return false;
238+
}
239+
240+
int stream_count = sending_streams_.size();
241+
242+
int muted_count = 0;
243+
for (const auto& kv : sending_streams_) {
244+
if (kv.first->GetMuted()) {
245+
muted_count++;
246+
}
247+
}
248+
249+
return muted_count != stream_count;
250+
}
251+
206252
} // namespace internal
207253

208254
rtc::scoped_refptr<AudioState> AudioState::Create(

audio/audio_state.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class AudioState : public webrtc::AudioState {
4747

4848
void SetStereoChannelSwapping(bool enable) override;
4949

50+
void OnMuteStreamChanged() override;
51+
5052
AudioDeviceModule* audio_device_module() {
5153
RTC_DCHECK(config_.audio_device_module);
5254
return config_.audio_device_module.get();
@@ -64,6 +66,9 @@ class AudioState : public webrtc::AudioState {
6466
void UpdateAudioTransportWithSendingStreams();
6567
void UpdateNullAudioPollerState() RTC_RUN_ON(&thread_checker_);
6668

69+
// Returns true when at least 1 stream exists and all streams are not muted.
70+
bool ShouldRecord();
71+
6772
SequenceChecker thread_checker_;
6873
SequenceChecker process_thread_checker_{SequenceChecker::kDetached};
6974
const webrtc::AudioState::Config config_;

audio/channel_send.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ class ChannelSend : public ChannelSendInterface,
9898
// Muting, Volume and Level.
9999
void SetInputMute(bool enable) override;
100100

101+
bool InputMute() const override;
102+
101103
// Stats.
102104
ANAStats GetANAStatistics() const override;
103105

@@ -161,8 +163,6 @@ class ChannelSend : public ChannelSendInterface,
161163
size_t payloadSize,
162164
int64_t absolute_capture_timestamp_ms) override;
163165

164-
bool InputMute() const;
165-
166166
int32_t SendRtpAudio(AudioFrameType frameType,
167167
uint8_t payloadType,
168168
uint32_t rtp_timestamp,

audio/channel_send.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class ChannelSendInterface {
9595
virtual bool SendTelephoneEventOutband(int event, int duration_ms) = 0;
9696
virtual void OnBitrateAllocation(BitrateAllocationUpdate update) = 0;
9797
virtual int GetTargetBitrate() const = 0;
98+
99+
virtual bool InputMute() const = 0;
98100
virtual void SetInputMute(bool muted) = 0;
99101

100102
virtual void ProcessAndEncodeAudio(

call/audio_send_stream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class AudioSendStream : public AudioSender {
190190
int event,
191191
int duration_ms) = 0;
192192

193+
virtual bool GetMuted() = 0;
193194
virtual void SetMuted(bool muted) = 0;
194195

195196
virtual Stats GetStats() const = 0;

call/audio_state.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ class AudioState : public rtc::RefCountInterface {
5959

6060
virtual void SetStereoChannelSwapping(bool enable) = 0;
6161

62+
// Notify the AudioState that a stream updated it's mute state.
63+
virtual void OnMuteStreamChanged() = 0;
64+
6265
static rtc::scoped_refptr<AudioState> Create(
6366
const AudioState::Config& config);
6467

media/engine/webrtc_voice_engine.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,9 @@ bool WebRtcVoiceMediaChannel::MuteStream(uint32_t ssrc, bool muted) {
22852285
ap->set_output_will_be_muted(all_muted);
22862286
}
22872287

2288+
// Notfy the AudioState that the mute state has updated.
2289+
engine_->audio_state()->OnMuteStreamChanged();
2290+
22882291
return true;
22892292
}
22902293

media/engine/webrtc_voice_engine.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface {
9393

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

9799
private:
98100
// Every option that is "set" will be applied. Every option not "set" will be
@@ -105,7 +107,6 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface {
105107

106108
webrtc::AudioDeviceModule* adm();
107109
webrtc::AudioProcessing* apm() const;
108-
webrtc::AudioState* audio_state();
109110

110111
std::vector<AudioCodec> CollectCodecs(
111112
const std::vector<webrtc::AudioCodecSpec>& specs) const;

modules/audio_device/audio_device_data_observer.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ class ADMWrapper : public AudioDeviceModule, public AudioTransport {
307307
}
308308
#endif // WEBRTC_IOS
309309

310+
int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const override {
311+
return impl_->SetAudioDeviceSink(sink);
312+
}
313+
310314
protected:
311315
rtc::scoped_refptr<AudioDeviceModule> impl_;
312316
AudioDeviceDataObserver* legacy_observer_ = nullptr;

modules/audio_device/audio_device_generic.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ class AudioDeviceGeneric {
135135
virtual int GetRecordAudioParameters(AudioParameters* params) const;
136136
#endif // WEBRTC_IOS
137137

138+
virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink) { return -1; }
139+
virtual int32_t GetPlayoutDevice() const { return -1; }
140+
virtual int32_t GetRecordingDevice() const { return -1; }
141+
138142
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0;
139143

140144
virtual ~AudioDeviceGeneric() {}

modules/audio_device/audio_device_impl.cc

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,17 @@ namespace webrtc {
7272

7373
rtc::scoped_refptr<AudioDeviceModule> AudioDeviceModule::Create(
7474
AudioLayer audio_layer,
75-
TaskQueueFactory* task_queue_factory) {
75+
TaskQueueFactory* task_queue_factory,
76+
bool bypass_voice_processing) {
7677
RTC_DLOG(LS_INFO) << __FUNCTION__;
77-
return AudioDeviceModule::CreateForTest(audio_layer, task_queue_factory);
78+
return AudioDeviceModule::CreateForTest(audio_layer, task_queue_factory, bypass_voice_processing);
7879
}
7980

8081
// static
8182
rtc::scoped_refptr<AudioDeviceModuleForTest> AudioDeviceModule::CreateForTest(
8283
AudioLayer audio_layer,
83-
TaskQueueFactory* task_queue_factory) {
84+
TaskQueueFactory* task_queue_factory,
85+
bool bypass_voice_processing) {
8486
RTC_DLOG(LS_INFO) << __FUNCTION__;
8587

8688
// The "AudioDeviceModule::kWindowsCoreAudio2" audio layer has its own
@@ -93,7 +95,7 @@ rtc::scoped_refptr<AudioDeviceModuleForTest> AudioDeviceModule::CreateForTest(
9395

9496
// Create the generic reference counted (platform independent) implementation.
9597
auto audio_device = rtc::make_ref_counted<AudioDeviceModuleImpl>(
96-
audio_layer, task_queue_factory);
98+
audio_layer, task_queue_factory, bypass_voice_processing);
9799

98100
// Ensure that the current platform is supported.
99101
if (audio_device->CheckPlatform() == -1) {
@@ -116,8 +118,13 @@ rtc::scoped_refptr<AudioDeviceModuleForTest> AudioDeviceModule::CreateForTest(
116118

117119
AudioDeviceModuleImpl::AudioDeviceModuleImpl(
118120
AudioLayer audio_layer,
119-
TaskQueueFactory* task_queue_factory)
120-
: audio_layer_(audio_layer), audio_device_buffer_(task_queue_factory) {
121+
TaskQueueFactory* task_queue_factory,
122+
bool bypass_voice_processing)
123+
: audio_layer_(audio_layer),
124+
#if defined(WEBRTC_IOS)
125+
bypass_voice_processing_(bypass_voice_processing),
126+
#endif
127+
audio_device_buffer_(task_queue_factory) {
121128
RTC_DLOG(LS_INFO) << __FUNCTION__;
122129
}
123130

@@ -280,7 +287,7 @@ int32_t AudioDeviceModuleImpl::CreatePlatformSpecificObjects() {
280287
#if defined(WEBRTC_IOS)
281288
if (audio_layer == kPlatformDefaultAudio) {
282289
audio_device_.reset(
283-
new ios_adm::AudioDeviceIOS(/*bypass_voice_processing=*/false));
290+
new ios_adm::AudioDeviceIOS(/*bypass_voice_processing=*/bypass_voice_processing_));
284291
RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized.";
285292
}
286293
// END #if defined(WEBRTC_IOS)
@@ -937,6 +944,27 @@ int AudioDeviceModuleImpl::GetRecordAudioParameters(
937944
}
938945
#endif // WEBRTC_IOS
939946

947+
int32_t AudioDeviceModuleImpl::SetAudioDeviceSink(AudioDeviceSink* sink) const {
948+
RTC_LOG(LS_INFO) << __FUNCTION__ << "(" << sink << ")";
949+
int32_t ok = audio_device_->SetAudioDeviceSink(sink);
950+
RTC_LOG(LS_INFO) << "output: " << ok;
951+
return ok;
952+
}
953+
954+
int32_t AudioDeviceModuleImpl::GetPlayoutDevice() const {
955+
RTC_LOG(LS_INFO) << __FUNCTION__;
956+
int32_t r = audio_device_->GetPlayoutDevice();
957+
RTC_LOG(LS_INFO) << "output: " << r;
958+
return r;
959+
}
960+
961+
int32_t AudioDeviceModuleImpl::GetRecordingDevice() const {
962+
RTC_LOG(LS_INFO) << __FUNCTION__;
963+
int32_t r = audio_device_->GetRecordingDevice();
964+
RTC_LOG(LS_INFO) << "output: " << r;
965+
return r;
966+
}
967+
940968
AudioDeviceModuleImpl::PlatformType AudioDeviceModuleImpl::Platform() const {
941969
RTC_LOG(LS_INFO) << __FUNCTION__;
942970
return platform_type_;

modules/audio_device/audio_device_impl.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
4343
int32_t AttachAudioBuffer();
4444

4545
AudioDeviceModuleImpl(AudioLayer audio_layer,
46-
TaskQueueFactory* task_queue_factory);
46+
TaskQueueFactory* task_queue_factory,
47+
bool bypass_voice_processing = false);
4748
~AudioDeviceModuleImpl() override;
4849

4950
// Retrieve the currently utilized audio layer
@@ -145,6 +146,10 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
145146
int GetRecordAudioParameters(AudioParameters* params) const override;
146147
#endif // WEBRTC_IOS
147148

149+
int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const override;
150+
int32_t GetPlayoutDevice() const override;
151+
int32_t GetRecordingDevice() const override;
152+
148153
#if defined(WEBRTC_ANDROID)
149154
// Only use this acccessor for test purposes on Android.
150155
AudioManager* GetAndroidAudioManagerForTest() {
@@ -165,7 +170,9 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
165170
AudioLayer audio_layer_;
166171
PlatformType platform_type_ = kPlatformNotSupported;
167172
bool initialized_ = false;
168-
#if defined(WEBRTC_ANDROID)
173+
#if defined(WEBRTC_IOS)
174+
bool bypass_voice_processing_;
175+
#elif defined(WEBRTC_ANDROID)
169176
// Should be declared first to ensure that it outlives other resources.
170177
std::unique_ptr<AudioManager> audio_manager_android_;
171178
#endif

modules/audio_device/include/audio_device.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ namespace webrtc {
2121

2222
class AudioDeviceModuleForTest;
2323

24+
// Sink for callbacks related to a audio device.
25+
class AudioDeviceSink {
26+
public:
27+
virtual ~AudioDeviceSink() = default;
28+
29+
// input/output devices updated or default device changed
30+
virtual void OnDevicesUpdated() = 0;
31+
};
32+
2433
class AudioDeviceModule : public rtc::RefCountInterface {
2534
public:
2635
enum AudioLayer {
@@ -56,12 +65,14 @@ class AudioDeviceModule : public rtc::RefCountInterface {
5665
// Creates a default ADM for usage in production code.
5766
static rtc::scoped_refptr<AudioDeviceModule> Create(
5867
AudioLayer audio_layer,
59-
TaskQueueFactory* task_queue_factory);
68+
TaskQueueFactory* task_queue_factory,
69+
bool bypass_voice_processing = false);
6070
// Creates an ADM with support for extra test methods. Don't use this factory
6171
// in production code.
6272
static rtc::scoped_refptr<AudioDeviceModuleForTest> CreateForTest(
6373
AudioLayer audio_layer,
64-
TaskQueueFactory* task_queue_factory);
74+
TaskQueueFactory* task_queue_factory,
75+
bool bypass_voice_processing = false);
6576

6677
// Retrieve the currently utilized audio layer
6778
virtual int32_t ActiveAudioLayer(AudioLayer* audioLayer) const = 0;
@@ -171,6 +182,10 @@ class AudioDeviceModule : public rtc::RefCountInterface {
171182
virtual int GetRecordAudioParameters(AudioParameters* params) const = 0;
172183
#endif // WEBRTC_IOS
173184

185+
virtual int32_t SetAudioDeviceSink(AudioDeviceSink* sink) const { return -1; }
186+
virtual int32_t GetPlayoutDevice() const { return -1; }
187+
virtual int32_t GetRecordingDevice() const { return -1; }
188+
174189
protected:
175190
~AudioDeviceModule() override {}
176191
};

0 commit comments

Comments
 (0)