| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" | 11 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" |
| 12 | 12 |
| 13 #include "webrtc/base/checks.h" | 13 #include "webrtc/base/checks.h" |
| 14 #include "webrtc/base/criticalsection.h" |
| 14 | 15 |
| 15 #import "webrtc/base/objc/RTCLogging.h" | 16 #import "webrtc/base/objc/RTCLogging.h" |
| 16 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" | 17 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession+Private.h" |
| 17 | 18 |
| 18 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; | 19 NSString * const kRTCAudioSessionErrorDomain = @"org.webrtc.RTCAudioSession"; |
| 19 NSInteger const kRTCAudioSessionErrorLockRequired = -1; | 20 NSInteger const kRTCAudioSessionErrorLockRequired = -1; |
| 20 | 21 |
| 21 // This class needs to be thread-safe because it is accessed from many threads. | 22 // This class needs to be thread-safe because it is accessed from many threads. |
| 22 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of | 23 // TODO(tkchin): Consider more granular locking. We're not expecting a lot of |
| 23 // lock contention so coarse locks should be fine for now. | 24 // lock contention so coarse locks should be fine for now. |
| 24 @implementation RTCAudioSession { | 25 @implementation RTCAudioSession { |
| 26 rtc::CriticalSection _crit; |
| 25 AVAudioSession *_session; | 27 AVAudioSession *_session; |
| 26 NSHashTable *_delegates; | 28 NSHashTable *_delegates; |
| 27 NSInteger _activationCount; | 29 NSInteger _activationCount; |
| 30 NSInteger _lockRecursionCount; |
| 28 BOOL _isActive; | 31 BOOL _isActive; |
| 29 BOOL _isLocked; | |
| 30 } | 32 } |
| 31 | 33 |
| 32 @synthesize session = _session; | 34 @synthesize session = _session; |
| 33 @synthesize lock = _lock; | |
| 34 | 35 |
| 35 + (instancetype)sharedInstance { | 36 + (instancetype)sharedInstance { |
| 36 static dispatch_once_t onceToken; | 37 static dispatch_once_t onceToken; |
| 37 static RTCAudioSession *sharedInstance = nil; | 38 static RTCAudioSession *sharedInstance = nil; |
| 38 dispatch_once(&onceToken, ^{ | 39 dispatch_once(&onceToken, ^{ |
| 39 sharedInstance = [[RTCAudioSession alloc] init]; | 40 sharedInstance = [[RTCAudioSession alloc] init]; |
| 40 }); | 41 }); |
| 41 return sharedInstance; | 42 return sharedInstance; |
| 42 } | 43 } |
| 43 | 44 |
| 44 - (instancetype)init { | 45 - (instancetype)init { |
| 45 if (self = [super init]) { | 46 if (self = [super init]) { |
| 46 _session = [AVAudioSession sharedInstance]; | 47 _session = [AVAudioSession sharedInstance]; |
| 47 _delegates = [NSHashTable weakObjectsHashTable]; | 48 _delegates = [NSHashTable weakObjectsHashTable]; |
| 48 _lock = [[NSRecursiveLock alloc] init]; | 49 |
| 49 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; | 50 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; |
| 50 [center addObserver:self | 51 [center addObserver:self |
| 51 selector:@selector(handleInterruptionNotification:) | 52 selector:@selector(handleInterruptionNotification:) |
| 52 name:AVAudioSessionInterruptionNotification | 53 name:AVAudioSessionInterruptionNotification |
| 53 object:nil]; | 54 object:nil]; |
| 54 [center addObserver:self | 55 [center addObserver:self |
| 55 selector:@selector(handleRouteChangeNotification:) | 56 selector:@selector(handleRouteChangeNotification:) |
| 56 name:AVAudioSessionRouteChangeNotification | 57 name:AVAudioSessionRouteChangeNotification |
| 57 object:nil]; | 58 object:nil]; |
| 58 // TODO(tkchin): Maybe listen to SilenceSecondaryAudioHintNotification. | 59 // TODO(tkchin): Maybe listen to SilenceSecondaryAudioHintNotification. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 79 } | 80 } |
| 80 | 81 |
| 81 - (BOOL)isActive { | 82 - (BOOL)isActive { |
| 82 @synchronized(self) { | 83 @synchronized(self) { |
| 83 return _isActive; | 84 return _isActive; |
| 84 } | 85 } |
| 85 } | 86 } |
| 86 | 87 |
| 87 - (BOOL)isLocked { | 88 - (BOOL)isLocked { |
| 88 @synchronized(self) { | 89 @synchronized(self) { |
| 89 return _isLocked; | 90 return _lockRecursionCount > 0; |
| 90 } | 91 } |
| 91 } | 92 } |
| 92 | 93 |
| 93 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { | 94 - (void)addDelegate:(id<RTCAudioSessionDelegate>)delegate { |
| 94 @synchronized(self) { | 95 @synchronized(self) { |
| 95 [_delegates addObject:delegate]; | 96 [_delegates addObject:delegate]; |
| 96 } | 97 } |
| 97 } | 98 } |
| 98 | 99 |
| 99 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate { | 100 - (void)removeDelegate:(id<RTCAudioSessionDelegate>)delegate { |
| 100 @synchronized(self) { | 101 @synchronized(self) { |
| 101 [_delegates removeObject:delegate]; | 102 [_delegates removeObject:delegate]; |
| 102 } | 103 } |
| 103 } | 104 } |
| 104 | 105 |
| 105 - (void)lockForConfiguration { | 106 - (void)lockForConfiguration { |
| 106 [_lock lock]; | 107 _crit.Enter(); |
| 107 @synchronized(self) { | 108 @synchronized(self) { |
| 108 _isLocked = YES; | 109 ++_lockRecursionCount; |
| 109 } | 110 } |
| 110 } | 111 } |
| 111 | 112 |
| 112 - (void)unlockForConfiguration { | 113 - (void)unlockForConfiguration { |
| 113 // Don't let threads other than the one that called lockForConfiguration | 114 // Don't let threads other than the one that called lockForConfiguration |
| 114 // unlock. | 115 // unlock. |
| 115 if ([_lock tryLock]) { | 116 if (_crit.TryEnter()) { |
| 116 @synchronized(self) { | 117 @synchronized(self) { |
| 117 _isLocked = NO; | 118 --_lockRecursionCount; |
| 118 } | 119 } |
| 119 // One unlock for the tryLock, and another one to actually unlock. If this | 120 // One unlock for the tryLock, and another one to actually unlock. If this |
| 120 // was called without anyone calling lock, the underlying NSRecursiveLock | 121 // was called without anyone calling lock, we will hit an assertion. |
| 121 // should spit out an error. | 122 _crit.Leave(); |
| 122 [_lock unlock]; | 123 _crit.Leave(); |
| 123 [_lock unlock]; | |
| 124 } | 124 } |
| 125 } | 125 } |
| 126 | 126 |
| 127 #pragma mark - AVAudioSession proxy methods | 127 #pragma mark - AVAudioSession proxy methods |
| 128 | 128 |
| 129 - (NSString *)category { | 129 - (NSString *)category { |
| 130 return self.session.category; | 130 return self.session.category; |
| 131 } | 131 } |
| 132 | 132 |
| 133 - (AVAudioSessionCategoryOptions)categoryOptions { | 133 - (AVAudioSessionCategoryOptions)categoryOptions { |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 } | 524 } |
| 525 } | 525 } |
| 526 | 526 |
| 527 - (void)notifyMediaServicesWereReset { | 527 - (void)notifyMediaServicesWereReset { |
| 528 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { | 528 for (id<RTCAudioSessionDelegate> delegate in self.delegates) { |
| 529 [delegate audioSessionMediaServicesWereReset:self]; | 529 [delegate audioSessionMediaServicesWereReset:self]; |
| 530 } | 530 } |
| 531 } | 531 } |
| 532 | 532 |
| 533 @end | 533 @end |
| OLD | NEW |