diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index f2602c27e1..bcd8056cfc 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -334,6 +334,7 @@ if (is_ios || is_mac) { "../rtc_base", "../rtc_base:checks", "../rtc_base:rtc_base_approved", + "../rtc_base/synchronization:mutex", ] } diff --git a/sdk/objc/components/audio/RTCAudioSession+Configuration.mm b/sdk/objc/components/audio/RTCAudioSession+Configuration.mm index b2753f282e..449f31e9dd 100644 --- a/sdk/objc/components/audio/RTCAudioSession+Configuration.mm +++ b/sdk/objc/components/audio/RTCAudioSession+Configuration.mm @@ -43,9 +43,6 @@ if (outError) { *outError = nil; } - if (![self checkLock:outError]) { - return NO; - } // Provide an error even if there isn't one so we can log it. We will not // return immediately on error in this function and instead try to set diff --git a/sdk/objc/components/audio/RTCAudioSession+Private.h b/sdk/objc/components/audio/RTCAudioSession+Private.h index 4c1eb1c44a..8496ca6bbc 100644 --- a/sdk/objc/components/audio/RTCAudioSession+Private.h +++ b/sdk/objc/components/audio/RTCAudioSession+Private.h @@ -35,8 +35,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, assign) BOOL isInterrupted; -- (BOOL)checkLock:(NSError **)outError; - /** Adds the delegate to the list of delegates, and places it at the front of * the list. This delegate will be notified before other delegates of * audio events. diff --git a/sdk/objc/components/audio/RTCAudioSession.mm b/sdk/objc/components/audio/RTCAudioSession.mm index 520b2d1d37..843ce95ff3 100644 --- a/sdk/objc/components/audio/RTCAudioSession.mm +++ b/sdk/objc/components/audio/RTCAudioSession.mm @@ -16,7 +16,7 @@ #include "rtc_base/atomic_ops.h" #include "rtc_base/checks.h" -#include "rtc_base/deprecated/recursive_critical_section.h" +#include "rtc_base/synchronization/mutex.h" #import "RTCAudioSessionConfiguration.h" #import "base/RTCLogging.h" @@ -35,10 +35,9 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; // TODO(tkchin): Consider more granular locking. We're not expecting a lot of // lock contention so coarse locks should be fine for now. @implementation RTC_OBJC_TYPE (RTCAudioSession) { - rtc::RecursiveCriticalSection _crit; + webrtc::Mutex _mutex; AVAudioSession *_session; volatile int _activationCount; - volatile int _lockRecursionCount; volatile int _webRTCSessionCount; BOOL _isActive; BOOL _useManualAudio; @@ -151,10 +150,6 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; } } -- (BOOL)isLocked { - return _lockRecursionCount > 0; -} - - (void)setUseManualAudio:(BOOL)useManualAudio { @synchronized(self) { if (_useManualAudio == useManualAudio) { @@ -234,20 +229,11 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; #pragma clang diagnostic ignored "-Wthread-safety-analysis" - (void)lockForConfiguration { - _crit.Enter(); - rtc::AtomicOps::Increment(&_lockRecursionCount); + _mutex.Lock(); } - (void)unlockForConfiguration { - // Don't let threads other than the one that called lockForConfiguration - // unlock. - if (_crit.TryEnter()) { - rtc::AtomicOps::Decrement(&_lockRecursionCount); - // One unlock for the tryLock, and another one to actually unlock. If this - // was called without anyone calling lock, we will hit an assertion. - _crit.Leave(); - _crit.Leave(); - } + _mutex.Unlock(); } #pragma clang diagnostic pop @@ -346,13 +332,8 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; return self.session.preferredIOBufferDuration; } -// TODO(tkchin): Simplify the amount of locking happening here. Likely that we -// can just do atomic increments / decrements. - (BOOL)setActive:(BOOL)active error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } int activationCount = _activationCount; if (!active && activationCount == 0) { RTCLogWarning(@"Attempting to deactivate without prior activation."); @@ -409,85 +390,52 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; - (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setCategory:category withOptions:options error:outError]; } - (BOOL)setMode:(NSString *)mode error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setMode:mode error:outError]; } - (BOOL)setInputGain:(float)gain error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setInputGain:gain error:outError]; } - (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setPreferredSampleRate:sampleRate error:outError]; } - (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setPreferredIOBufferDuration:duration error:outError]; } - (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setPreferredInputNumberOfChannels:count error:outError]; } - (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setPreferredOutputNumberOfChannels:count error:outError]; } - (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session overrideOutputAudioPort:portOverride error:outError]; } - (BOOL)setPreferredInput:(AVAudioSessionPortDescription *)inPort error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setPreferredInput:inPort error:outError]; } - (BOOL)setInputDataSource:(AVAudioSessionDataSourceDescription *)dataSource error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setInputDataSource:dataSource error:outError]; } - (BOOL)setOutputDataSource:(AVAudioSessionDataSourceDescription *)dataSource error:(NSError **)outError { - if (![self checkLock:outError]) { - return NO; - } return [self.session setOutputDataSource:dataSource error:outError]; } @@ -608,18 +556,6 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; #pragma mark - Private -+ (NSError *)lockError { - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: - @"Must call lockForConfiguration before calling this method." - }; - NSError *error = - [[NSError alloc] initWithDomain:kRTCAudioSessionErrorDomain - code:kRTCAudioSessionErrorLockRequired - userInfo:userInfo]; - return error; -} - - (std::vector<__weak id >)delegates { @synchronized(self) { // Note: this returns a copy. @@ -681,25 +617,10 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; } } -- (BOOL)checkLock:(NSError **)outError { - // Check ivar instead of trying to acquire lock so that we won't accidentally - // acquire lock if it hasn't already been called. - if (!self.isLocked) { - if (outError) { - *outError = [RTC_OBJC_TYPE(RTCAudioSession) lockError]; - } - return NO; - } - return YES; -} - - (BOOL)beginWebRTCSession:(NSError **)outError { if (outError) { *outError = nil; } - if (![self checkLock:outError]) { - return NO; - } rtc::AtomicOps::Increment(&_webRTCSessionCount); [self notifyDidStartPlayOrRecord]; return YES; @@ -709,9 +630,6 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; if (outError) { *outError = nil; } - if (![self checkLock:outError]) { - return NO; - } rtc::AtomicOps::Decrement(&_webRTCSessionCount); [self notifyDidStopPlayOrRecord]; return YES; @@ -721,9 +639,6 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; if (outError) { *outError = nil; } - if (![self checkLock:outError]) { - return NO; - } RTCLog(@"Configuring audio session for WebRTC."); // Configure the AVAudioSession and activate it. @@ -784,9 +699,6 @@ NSString * const kRTCAudioSessionOutputVolumeSelector = @"outputVolume"; if (outError) { *outError = nil; } - if (![self checkLock:outError]) { - return NO; - } RTCLog(@"Unconfiguring audio session for WebRTC."); [self setActive:NO error:outError]; diff --git a/sdk/objc/unittests/RTCAudioSessionTest.mm b/sdk/objc/unittests/RTCAudioSessionTest.mm index 9c4775a2be..805f601bdd 100644 --- a/sdk/objc/unittests/RTCAudioSessionTest.mm +++ b/sdk/objc/unittests/RTCAudioSessionTest.mm @@ -113,26 +113,10 @@ @interface RTCAudioSessionTest : NSObject -- (void)testLockForConfiguration; - @end @implementation RTCAudioSessionTest -- (void)testLockForConfiguration { - RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; - - for (size_t i = 0; i < 2; i++) { - [session lockForConfiguration]; - EXPECT_TRUE(session.isLocked); - } - for (size_t i = 0; i < 2; i++) { - EXPECT_TRUE(session.isLocked); - [session unlockForConfiguration]; - } - EXPECT_FALSE(session.isLocked); -} - - (void)testAddAndRemoveDelegates { RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance]; NSMutableArray *delegates = [NSMutableArray array]; @@ -264,7 +248,6 @@ OCMLocation *OCMMakeLocation(id testCase, const char *fileCString, int line){ RTC_OBJC_TYPE(RTCAudioSession) *audioSession = mockAudioSession; EXPECT_EQ(0, audioSession.activationCount); [audioSession lockForConfiguration]; - EXPECT_TRUE([audioSession checkLock:nil]); // configureWebRTCSession is forced to fail in the above mock interface, // so activationCount should remain 0 OCMExpect([[mockAVAudioSession ignoringNonObjectArgs] setActive:YES @@ -316,11 +299,6 @@ class AudioSessionTest : public ::testing::Test { } }; -TEST_F(AudioSessionTest, LockForConfiguration) { - RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; - [test testLockForConfiguration]; -} - TEST_F(AudioSessionTest, AddAndRemoveDelegates) { RTCAudioSessionTest *test = [[RTCAudioSessionTest alloc] init]; [test testAddAndRemoveDelegates];