Skip to content

Commit 5a34169

Browse files
hiroshihoriecloudwebrtc
authored andcommitted
AudioUnit: Don't rely on category switch for mic indicator to turn off (#52)
* progress * tweak * clean * simplify audio unit restart call to SetupAudioBuffersForActiveAudioSession() might not be needed since sample rate won't change during restart. This might help reduce the unwanted noise when restarting audio unit. * clean
1 parent decb048 commit 5a34169

File tree

9 files changed

+63
-106
lines changed

9 files changed

+63
-106
lines changed

sdk/objc/components/audio/RTCAudioSession+Private.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ NS_ASSUME_NONNULL_BEGIN
3535
*/
3636
@property(nonatomic, assign) BOOL isInterrupted;
3737

38-
@property(nonatomic, strong) NSString *activeCategory;
39-
4038
/** Adds the delegate to the list of delegates, and places it at the front of
4139
* the list. This delegate will be notified before other delegates of
4240
* audio events.

sdk/objc/components/audio/RTCAudioSession.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,6 @@ RTC_OBJC_EXPORT
102102
- (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession
103103
audioUnitStartFailedWithError:(NSError *)error;
104104

105-
/** Called when audio session changed from output-only to input & output */
106-
- (void)audioSessionDidChangeRecordingEnabled:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession;
107-
108105
@end
109106

110107
/** This is a protocol used to inform RTCAudioSession when the audio session

sdk/objc/components/audio/RTCAudioSession.mm

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ - (instancetype)initWithAudioSession:(id)audioSession {
114114
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
115115
context:(__bridge void *)RTC_OBJC_TYPE(RTCAudioSession).class];
116116

117-
_activeCategory = _session.category;
118-
119117
RTCLog(@"RTC_OBJC_TYPE(RTCAudioSession) (%p): init.", self);
120118
}
121119
return self;
@@ -543,13 +541,6 @@ - (void)handleRouteChangeNotification:(NSNotification *)notification {
543541
break;
544542
case AVAudioSessionRouteChangeReasonCategoryChange:
545543
RTCLog(@"Audio route changed: CategoryChange to :%@", self.session.category);
546-
{
547-
if (![_session.category isEqualToString:_activeCategory]) {
548-
_activeCategory = _session.category;
549-
RTCLog(@"Audio route changed: Restarting Audio Unit");
550-
[self notifyDidChangeAudioSessionRecordingEnabled];
551-
}
552-
}
553544
break;
554545
case AVAudioSessionRouteChangeReasonOverride:
555546
RTCLog(@"Audio route changed: Override");
@@ -1005,13 +996,4 @@ - (void)notifyFailedToSetActive:(BOOL)active error:(NSError *)error {
1005996
}
1006997
}
1007998

1008-
- (void)notifyDidChangeAudioSessionRecordingEnabled {
1009-
for (auto delegate : self.delegates) {
1010-
SEL sel = @selector(audioSessionDidChangeRecordingEnabled:);
1011-
if ([delegate respondsToSelector:sel]) {
1012-
[delegate audioSessionDidChangeRecordingEnabled:self];
1013-
}
1014-
}
1015-
}
1016-
1017999
@end

sdk/objc/components/audio/RTCNativeAudioSessionDelegateAdapter.mm

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,4 @@ - (void)audioSession:(RTC_OBJC_TYPE(RTCAudioSession) *)audioSession
8686
_observer->OnChangedOutputVolume();
8787
}
8888

89-
- (void)audioSessionDidChangeRecordingEnabled:(RTC_OBJC_TYPE(RTCAudioSession) *)session {
90-
// re-trigger audio unit init, by using interrupt ended callback
91-
_observer->OnChangedRecordingEnabled();
92-
}
93-
9489
@end

sdk/objc/native/src/audio/audio_device_ios.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ class AudioDeviceIOS : public AudioDeviceGeneric,
149149
void OnValidRouteChange() override;
150150
void OnCanPlayOrRecordChange(bool can_play_or_record) override;
151151
void OnChangedOutputVolume() override;
152-
void OnChangedRecordingEnabled() override;
153152

154153
// VoiceProcessingAudioUnitObserver methods.
155154
OSStatus OnDeliverRecordedData(AudioUnitRenderActionFlags* flags,
@@ -174,7 +173,8 @@ class AudioDeviceIOS : public AudioDeviceGeneric,
174173
void HandleSampleRateChange();
175174
void HandlePlayoutGlitchDetected();
176175
void HandleOutputVolumeChange();
177-
void HandleAudioSessionRecordingEnabledChange();
176+
177+
bool RestartAudioUnit(bool enable_input);
178178

179179
// Uses current `playout_parameters_` and `record_parameters_` to inform the
180180
// audio device buffer (ADB) about our internal audio parameters.
@@ -204,7 +204,7 @@ class AudioDeviceIOS : public AudioDeviceGeneric,
204204

205205
// Activates our audio session, creates and initializes the voice-processing
206206
// audio unit and verifies that we got the preferred native audio parameters.
207-
bool InitPlayOrRecord();
207+
bool InitPlayOrRecord(bool enable_input);
208208

209209
// Closes and deletes the voice-processing I/O unit.
210210
void ShutdownPlayOrRecord();
@@ -264,19 +264,19 @@ class AudioDeviceIOS : public AudioDeviceGeneric,
264264
// will be changed dynamically to account for this behavior.
265265
rtc::BufferT<int16_t> record_audio_buffer_;
266266

267+
bool recording_is_initialized_;
268+
267269
// Set to 1 when recording is active and 0 otherwise.
268270
std::atomic<int> recording_;
269271

272+
bool playout_is_initialized_;
273+
270274
// Set to 1 when playout is active and 0 otherwise.
271275
std::atomic<int> playing_;
272276

273277
// Set to true after successful call to Init(), false otherwise.
274278
bool initialized_ RTC_GUARDED_BY(thread_);
275279

276-
// Set to true after successful call to InitRecording() or InitPlayout(),
277-
// false otherwise.
278-
bool audio_is_initialized_;
279-
280280
// Set to true if audio session is interrupted, false otherwise.
281281
bool is_interrupted_;
282282

sdk/objc/native/src/audio/audio_device_ios.mm

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,11 @@ static void LogDeviceInfo() {
9494
: bypass_voice_processing_(bypass_voice_processing),
9595
audio_device_buffer_(nullptr),
9696
audio_unit_(nullptr),
97+
recording_is_initialized_(false),
9798
recording_(0),
99+
playout_is_initialized_(false),
98100
playing_(0),
99101
initialized_(false),
100-
audio_is_initialized_(false),
101102
is_interrupted_(false),
102103
has_configured_session_(false),
103104
num_detected_playout_glitches_(0),
@@ -176,48 +177,57 @@ static void LogDeviceInfo() {
176177
LOGI() << "InitPlayout";
177178
RTC_DCHECK_RUN_ON(thread_);
178179
RTC_DCHECK(initialized_);
179-
RTC_DCHECK(!audio_is_initialized_);
180+
RTC_DCHECK(!playout_is_initialized_);
180181
RTC_DCHECK(!playing_.load());
181-
if (!audio_is_initialized_) {
182-
if (!InitPlayOrRecord()) {
182+
if (!recording_is_initialized_) {
183+
// recording not initialized yet, init with no input
184+
if (!InitPlayOrRecord(false)) {
183185
RTC_LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitPlayout!";
184186
return -1;
185187
}
186188
}
187-
audio_is_initialized_ = true;
189+
190+
playout_is_initialized_ = true;
191+
188192
return 0;
189193
}
190194

191195
bool AudioDeviceIOS::PlayoutIsInitialized() const {
192196
RTC_DCHECK_RUN_ON(thread_);
193-
return audio_is_initialized_;
197+
return playout_is_initialized_;
194198
}
195199

196200
bool AudioDeviceIOS::RecordingIsInitialized() const {
197201
RTC_DCHECK_RUN_ON(thread_);
198-
return audio_is_initialized_;
202+
return recording_is_initialized_;
199203
}
200204

201205
int32_t AudioDeviceIOS::InitRecording() {
202206
LOGI() << "InitRecording";
203207
RTC_DCHECK_RUN_ON(thread_);
204208
RTC_DCHECK(initialized_);
205-
RTC_DCHECK(!audio_is_initialized_);
209+
RTC_DCHECK(!recording_is_initialized_);
206210
RTC_DCHECK(!recording_.load());
207-
if (!audio_is_initialized_) {
208-
if (!InitPlayOrRecord()) {
211+
if (!playout_is_initialized_) {
212+
// playout not initialized yet, init with input
213+
if (!InitPlayOrRecord(true)) {
209214
RTC_LOG_F(LS_ERROR) << "InitPlayOrRecord failed for InitRecording!";
210215
return -1;
211216
}
217+
} else {
218+
// playout already initialized, restart audio unit with input
219+
RestartAudioUnit(true);
212220
}
213-
audio_is_initialized_ = true;
221+
222+
recording_is_initialized_ = true;
223+
214224
return 0;
215225
}
216226

217227
int32_t AudioDeviceIOS::StartPlayout() {
218228
LOGI() << "StartPlayout";
219229
RTC_DCHECK_RUN_ON(thread_);
220-
RTC_DCHECK(audio_is_initialized_);
230+
RTC_DCHECK(playout_is_initialized_);
221231
RTC_DCHECK(!playing_.load());
222232
RTC_DCHECK(audio_unit_);
223233
if (fine_audio_buffer_) {
@@ -242,12 +252,13 @@ static void LogDeviceInfo() {
242252
int32_t AudioDeviceIOS::StopPlayout() {
243253
LOGI() << "StopPlayout";
244254
RTC_DCHECK_RUN_ON(thread_);
245-
if (!audio_is_initialized_ || !playing_.load()) {
255+
if (!playout_is_initialized_ || !playing_.load()) {
246256
return 0;
247257
}
248258
if (!recording_.load()) {
249259
ShutdownPlayOrRecord();
250-
audio_is_initialized_ = false;
260+
261+
recording_is_initialized_ = false;
251262
}
252263
playing_.store(0, std::memory_order_release);
253264

@@ -273,7 +284,7 @@ static void LogDeviceInfo() {
273284
int32_t AudioDeviceIOS::StartRecording() {
274285
LOGI() << "StartRecording";
275286
RTC_DCHECK_RUN_ON(thread_);
276-
RTC_DCHECK(audio_is_initialized_);
287+
RTC_DCHECK(recording_is_initialized_);
277288
RTC_DCHECK(!recording_.load());
278289
RTC_DCHECK(audio_unit_);
279290
if (fine_audio_buffer_) {
@@ -296,12 +307,16 @@ static void LogDeviceInfo() {
296307
int32_t AudioDeviceIOS::StopRecording() {
297308
LOGI() << "StopRecording";
298309
RTC_DCHECK_RUN_ON(thread_);
299-
if (!audio_is_initialized_ || !recording_.load()) {
310+
if (!recording_is_initialized_ || !recording_.load()) {
300311
return 0;
301312
}
302313
if (!playing_.load()) {
303314
ShutdownPlayOrRecord();
304-
audio_is_initialized_ = false;
315+
316+
playout_is_initialized_ = false;
317+
} else if (playout_is_initialized_) {
318+
// restart audio unit with no input
319+
RestartAudioUnit(false);
305320
}
306321
recording_.store(0, std::memory_order_release);
307322
return 0;
@@ -360,11 +375,6 @@ static void LogDeviceInfo() {
360375
thread_->PostTask(SafeTask(safety_, [this] { HandleOutputVolumeChange(); }));
361376
}
362377

363-
void AudioDeviceIOS::OnChangedRecordingEnabled() {
364-
RTC_DCHECK(thread_);
365-
thread_->PostTask(SafeTask(safety_, [this] { HandleAudioSessionRecordingEnabledChange(); }));
366-
}
367-
368378
OSStatus AudioDeviceIOS::OnDeliverRecordedData(AudioUnitRenderActionFlags* flags,
369379
const AudioTimeStamp* time_stamp,
370380
UInt32 bus_number,
@@ -584,7 +594,7 @@ static void LogDeviceInfo() {
584594
SetupAudioBuffersForActiveAudioSession();
585595

586596
// Initialize the audio unit again with the new sample rate.
587-
if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) {
597+
if (!audio_unit_->Initialize(playout_parameters_.sample_rate(), recording_is_initialized_)) {
588598
RTCLogError(@"Failed to initialize the audio unit with sample rate: %d",
589599
playout_parameters_.sample_rate());
590600
return;
@@ -638,59 +648,44 @@ static void LogDeviceInfo() {
638648
last_output_volume_change_time_ = rtc::TimeMillis();
639649
}
640650

641-
void AudioDeviceIOS::HandleAudioSessionRecordingEnabledChange() {
651+
bool AudioDeviceIOS::RestartAudioUnit(bool enable_input) {
642652
RTC_DCHECK_RUN_ON(&io_thread_checker_);
643653

644-
LOGI() << "HandleAudioSessionRecordingEnabledChange";
654+
LOGI() << "RestartAudioUnit";
645655

646656
// If we don't have an audio unit yet, or the audio unit is uninitialized,
647657
// there is no work to do.
648658
if (!audio_unit_ || audio_unit_->GetState() < VoiceProcessingAudioUnit::kInitialized) {
649-
return;
659+
return false;
650660
}
651661

652-
// The audio unit is already initialized or started.
653-
// Check to see if the sample rate or buffer size has changed.
654-
RTC_OBJC_TYPE(RTCAudioSession)* session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
655-
const double session_sample_rate = session.sampleRate;
656-
657-
// Extra sanity check to ensure that the new sample rate is valid.
658-
if (session_sample_rate <= 0.0) {
659-
RTCLogError(@"Sample rate is invalid: %f", session_sample_rate);
660-
LOGI() << "Sample rate is invalid " << session_sample_rate;
661-
return;
662-
}
663-
// We need to adjust our format and buffer sizes.
664-
// The stream format is about to be changed and it requires that we first
665-
// stop and uninitialize the audio unit to deallocate its resources.
666-
RTCLog(@"Stopping and uninitializing audio unit to adjust buffers.");
667662
bool restart_audio_unit = false;
668663
if (audio_unit_->GetState() == VoiceProcessingAudioUnit::kStarted) {
669664
audio_unit_->Stop();
670-
restart_audio_unit = true;
671665
PrepareForNewStart();
666+
restart_audio_unit = true;
672667
}
668+
673669
if (audio_unit_->GetState() == VoiceProcessingAudioUnit::kInitialized) {
674670
audio_unit_->Uninitialize();
675671
}
676672

677-
// Allocate new buffers given the new stream format.
678-
SetupAudioBuffersForActiveAudioSession();
673+
// Initialize the audio unit again with the same sample rate.
674+
const double sample_rate = playout_parameters_.sample_rate();
679675

680-
// Initialize the audio unit again with the new sample rate.
681-
RTC_DCHECK_EQ(playout_parameters_.sample_rate(), session_sample_rate);
682-
if (!audio_unit_->Initialize(session_sample_rate)) {
683-
RTCLogError(@"Failed to initialize the audio unit with sample rate: %f", session_sample_rate);
684-
return;
676+
if (!audio_unit_->Initialize(sample_rate, enable_input)) {
677+
RTCLogError(@"Failed to initialize the audio unit with sample rate: %f", sample_rate);
678+
return false;
685679
}
686680

687681
// Restart the audio unit if it was already running.
688682
if (restart_audio_unit && !audio_unit_->Start()) {
689-
RTCLogError(@"Failed to start audio unit with sample rate: %f", session_sample_rate);
690-
return;
683+
RTCLogError(@"Failed to start audio unit with sample rate: %f", sample_rate);
684+
return false;
691685
}
692686

693687
LOGI() << "Successfully enabled audio unit for recording.";
688+
return true;
694689
}
695690

696691
void AudioDeviceIOS::UpdateAudioDeviceBuffer() {
@@ -786,7 +781,7 @@ static void LogDeviceInfo() {
786781

787782
// If we're not initialized we don't need to do anything. Audio unit will
788783
// be initialized on initialization.
789-
if (!audio_is_initialized_) return;
784+
if (!playout_is_initialized_ && !recording_is_initialized_) return;
790785

791786
// If we're initialized, we must have an audio unit.
792787
RTC_DCHECK(audio_unit_);
@@ -824,7 +819,7 @@ static void LogDeviceInfo() {
824819
RTCLog(@"Initializing audio unit for UpdateAudioUnit");
825820
ConfigureAudioSession();
826821
SetupAudioBuffersForActiveAudioSession();
827-
if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) {
822+
if (!audio_unit_->Initialize(playout_parameters_.sample_rate(), recording_is_initialized_)) {
828823
RTCLogError(@"Failed to initialize audio unit.");
829824
return;
830825
}
@@ -914,7 +909,7 @@ static void LogDeviceInfo() {
914909
RTCLog(@"Unconfigured audio session.");
915910
}
916911

917-
bool AudioDeviceIOS::InitPlayOrRecord() {
912+
bool AudioDeviceIOS::InitPlayOrRecord(bool enable_input) {
918913
LOGI() << "InitPlayOrRecord";
919914
RTC_DCHECK_RUN_ON(thread_);
920915

@@ -950,7 +945,7 @@ static void LogDeviceInfo() {
950945
return false;
951946
}
952947
SetupAudioBuffersForActiveAudioSession();
953-
audio_unit_->Initialize(playout_parameters_.sample_rate());
948+
audio_unit_->Initialize(playout_parameters_.sample_rate(), enable_input);
954949
}
955950

956951
// Release the lock.

sdk/objc/native/src/audio/audio_session_observer.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ class AudioSessionObserver {
3232

3333
virtual void OnChangedOutputVolume() = 0;
3434

35-
virtual void OnChangedRecordingEnabled() = 0;
36-
3735
protected:
3836
virtual ~AudioSessionObserver() {}
3937
};

sdk/objc/native/src/audio/voice_processing_audio_unit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class VoiceProcessingAudioUnit {
7575
VoiceProcessingAudioUnit::State GetState() const;
7676

7777
// Initializes the underlying audio unit with the given sample rate.
78-
bool Initialize(Float64 sample_rate);
78+
bool Initialize(Float64 sample_rate, bool enable_input);
7979

8080
// Starts the underlying audio unit.
8181
OSStatus Start();

0 commit comments

Comments
 (0)