Enhance RTCUIApplicationStatusObserver thread safety.
Add locking around waiting for initialization to finish, since calling dispatch_block_wait from multiple threads leads to undefined behavior. Initialize RTCUIApplicationStatusObserver earlier to give the initialization block more time to run on the main thread before starting to query the application state. http://www.dailymotion.com/video/x2mckmh BUG=b/65558688 Review-Url: https://codereview.webrtc.org/3009383002 Cr-Commit-Position: refs/heads/master@{#19822}
This commit is contained in:
parent
f54573bd3b
commit
9a85f0782e
@ -15,6 +15,7 @@
|
|||||||
@interface RTCUIApplicationStatusObserver : NSObject
|
@interface RTCUIApplicationStatusObserver : NSObject
|
||||||
|
|
||||||
+ (instancetype)sharedInstance;
|
+ (instancetype)sharedInstance;
|
||||||
|
+ (void)prepareForUse;
|
||||||
|
|
||||||
- (BOOL)isApplicationActive;
|
- (BOOL)isApplicationActive;
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
@implementation RTCUIApplicationStatusObserver {
|
@implementation RTCUIApplicationStatusObserver {
|
||||||
BOOL _initialized;
|
BOOL _initialized;
|
||||||
dispatch_block_t _initializeBlock;
|
dispatch_block_t _initializeBlock;
|
||||||
|
dispatch_semaphore_t _waitForInitializeSemaphore;
|
||||||
UIApplicationState _state;
|
UIApplicationState _state;
|
||||||
|
|
||||||
id<NSObject> _activeObserver;
|
id<NSObject> _activeObserver;
|
||||||
@ -45,6 +46,12 @@
|
|||||||
return sharedInstance;
|
return sharedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to make sure observers are added and the initialization block is
|
||||||
|
// scheduled to run on the main queue.
|
||||||
|
+ (void)prepareForUse {
|
||||||
|
__unused RTCUIApplicationStatusObserver *observer = [self sharedInstance];
|
||||||
|
}
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||||
@ -65,6 +72,7 @@
|
|||||||
[UIApplication sharedApplication].applicationState;
|
[UIApplication sharedApplication].applicationState;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
_waitForInitializeSemaphore = dispatch_semaphore_create(1);
|
||||||
_initialized = NO;
|
_initialized = NO;
|
||||||
_initializeBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
|
_initializeBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
|
||||||
weakSelf.state = [UIApplication sharedApplication].applicationState;
|
weakSelf.state = [UIApplication sharedApplication].applicationState;
|
||||||
@ -84,11 +92,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isApplicationActive {
|
- (BOOL)isApplicationActive {
|
||||||
|
// NOTE: The function `dispatch_block_wait` can only legally be called once.
|
||||||
|
// Because of this, if several threads call the `isApplicationActive` method before
|
||||||
|
// the `_initializeBlock` has been executed, instead of multiple threads calling
|
||||||
|
// `dispatch_block_wait`, the other threads need to wait for the first waiting thread
|
||||||
|
// instead.
|
||||||
|
if (!_initialized) {
|
||||||
|
dispatch_semaphore_wait(_waitForInitializeSemaphore, DISPATCH_TIME_FOREVER);
|
||||||
if (!_initialized) {
|
if (!_initialized) {
|
||||||
long ret = dispatch_block_wait(_initializeBlock,
|
long ret = dispatch_block_wait(_initializeBlock,
|
||||||
dispatch_time(DISPATCH_TIME_NOW, 10.0 * NSEC_PER_SEC));
|
dispatch_time(DISPATCH_TIME_NOW, 10.0 * NSEC_PER_SEC));
|
||||||
RTC_DCHECK_EQ(ret, 0);
|
RTC_DCHECK_EQ(ret, 0);
|
||||||
}
|
}
|
||||||
|
dispatch_semaphore_signal(_waitForInitializeSemaphore);
|
||||||
|
}
|
||||||
return _state == UIApplicationStateActive;
|
return _state == UIApplicationStateActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -67,6 +67,16 @@ void decompressionOutputCallback(void *decoder,
|
|||||||
RTCVideoDecoderCallback _callback;
|
RTCVideoDecoderCallback _callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
#if defined(WEBRTC_IOS)
|
||||||
|
[RTCUIApplicationStatusObserver prepareForUse];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[self destroyDecompressionSession];
|
[self destroyDecompressionSession];
|
||||||
[self setVideoFormat:nullptr];
|
[self setVideoFormat:nullptr];
|
||||||
|
|||||||
@ -301,6 +301,10 @@ CFStringRef ExtractProfile(const cricket::VideoCodec &codec) {
|
|||||||
_profile = ExtractProfile([codecInfo nativeVideoCodec]);
|
_profile = ExtractProfile([codecInfo nativeVideoCodec]);
|
||||||
LOG(LS_INFO) << "Using profile " << CFStringToString(_profile);
|
LOG(LS_INFO) << "Using profile " << CFStringToString(_profile);
|
||||||
RTC_CHECK([codecInfo.name isEqualToString:@"H264"]);
|
RTC_CHECK([codecInfo.name isEqualToString:@"H264"]);
|
||||||
|
|
||||||
|
#if defined(WEBRTC_IOS)
|
||||||
|
[RTCUIApplicationStatusObserver prepareForUse];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user