diff --git a/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.h b/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.h index ff38628383..a2064df5db 100644 --- a/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.h +++ b/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.h @@ -15,6 +15,7 @@ @interface RTCUIApplicationStatusObserver : NSObject + (instancetype)sharedInstance; ++ (void)prepareForUse; - (BOOL)isApplicationActive; diff --git a/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.m b/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.m index 1d2aab48e8..7134773610 100644 --- a/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.m +++ b/webrtc/sdk/objc/Framework/Classes/Common/RTCUIApplicationStatusObserver.m @@ -26,6 +26,7 @@ @implementation RTCUIApplicationStatusObserver { BOOL _initialized; dispatch_block_t _initializeBlock; + dispatch_semaphore_t _waitForInitializeSemaphore; UIApplicationState _state; id _activeObserver; @@ -45,6 +46,12 @@ 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 { if (self = [super init]) { NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; @@ -65,6 +72,7 @@ [UIApplication sharedApplication].applicationState; }]; + _waitForInitializeSemaphore = dispatch_semaphore_create(1); _initialized = NO; _initializeBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{ weakSelf.state = [UIApplication sharedApplication].applicationState; @@ -84,10 +92,19 @@ } - (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) { - long ret = dispatch_block_wait(_initializeBlock, - dispatch_time(DISPATCH_TIME_NOW, 10.0 * NSEC_PER_SEC)); - RTC_DCHECK_EQ(ret, 0); + dispatch_semaphore_wait(_waitForInitializeSemaphore, DISPATCH_TIME_FOREVER); + if (!_initialized) { + long ret = dispatch_block_wait(_initializeBlock, + dispatch_time(DISPATCH_TIME_NOW, 10.0 * NSEC_PER_SEC)); + RTC_DCHECK_EQ(ret, 0); + } + dispatch_semaphore_signal(_waitForInitializeSemaphore); } return _state == UIApplicationStateActive; } diff --git a/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoDecoderH264.mm b/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoDecoderH264.mm index f657f9c2f1..b19cb43bd1 100644 --- a/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoDecoderH264.mm +++ b/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoDecoderH264.mm @@ -67,6 +67,16 @@ void decompressionOutputCallback(void *decoder, RTCVideoDecoderCallback _callback; } +- (instancetype)init { + if (self = [super init]) { +#if defined(WEBRTC_IOS) + [RTCUIApplicationStatusObserver prepareForUse]; +#endif + } + + return self; +} + - (void)dealloc { [self destroyDecompressionSession]; [self setVideoFormat:nullptr]; diff --git a/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoEncoderH264.mm b/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoEncoderH264.mm index 0fcefeef02..6e2b568273 100644 --- a/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoEncoderH264.mm +++ b/webrtc/sdk/objc/Framework/Classes/VideoToolbox/RTCVideoEncoderH264.mm @@ -301,6 +301,10 @@ CFStringRef ExtractProfile(const cricket::VideoCodec &codec) { _profile = ExtractProfile([codecInfo nativeVideoCodec]); LOG(LS_INFO) << "Using profile " << CFStringToString(_profile); RTC_CHECK([codecInfo.name isEqualToString:@"H264"]); + +#if defined(WEBRTC_IOS) + [RTCUIApplicationStatusObserver prepareForUse]; +#endif } return self; }