Changeset 212844 in webkit
- Timestamp:
- Feb 22, 2017, 12:06:57 PM (10 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
-
ChangeLog (modified) (1 diff)
-
platform/mediastream/mac/AVMediaCaptureSource.h (modified) (3 diffs)
-
platform/mediastream/mac/AVMediaCaptureSource.mm (modified) (14 diffs)
-
platform/mediastream/mac/AVVideoCaptureSource.mm (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r212843 r212844 1 2017-02-22 Eric Carlson <eric.carlson@apple.com> 2 3 [MediaStream iOS] Respond to capture interruptions and notifications 4 https://bugs.webkit.org/show_bug.cgi?id=168610 5 6 Reviewed by Jer Noble. 7 8 * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaStreamAVFObjC.mm: 9 (WebCore::MediaPlayerPrivateMediaStreamAVFObjC::ensureLayer): Drive-by cleanup: don't create 10 a sample buffer display layer unless there is an active video track. 11 12 * platform/mediastream/mac/AVMediaCaptureSource.h: 13 * platform/mediastream/mac/AVMediaCaptureSource.mm: 14 (WebCore::AVMediaCaptureSource::AVMediaCaptureSource): Add static_asserts to ensure that 15 WebCore::InterruptionReason values map directly to AVCaptureSessionInterruptionReason values. 16 (WebCore::AVMediaCaptureSource::~AVMediaCaptureSource): Minor cleanup. 17 (WebCore::AVMediaCaptureSource::startProducingData): Start listening for notifications before 18 starting the session. 19 (WebCore::AVMediaCaptureSource::stopProducingData): Remove the notification observers before 20 stopping the session. 21 (WebCore::AVMediaCaptureSource::setupSession): Minor style cleanup. 22 (WebCore::AVMediaCaptureSource::captureSessionRuntimeError): New. When the error is AVErrorMediaServicesWereReset, 23 sometimes caused by a mediaserverd crash, try to restart the session one time. 24 (WebCore::AVMediaCaptureSource::captureSessionBeginInterruption): Store the interruption reason. 25 (WebCore::AVMediaCaptureSource::captureSessionEndInterruption): Try to restart the session if 26 it was interrupted because the app went into multi-app layout mode. 27 (WebCore::sessionKVOProperties): Drive-by cleanup. 28 (-[WebCoreAVMediaCaptureSourceObserver initWithCallback:]): 29 (-[WebCoreAVMediaCaptureSourceObserver disconnect]): 30 (-[WebCoreAVMediaCaptureSourceObserver addNotificationObservers]): 31 (-[WebCoreAVMediaCaptureSourceObserver removeNotificationObservers]): 32 (-[WebCoreAVMediaCaptureSourceObserver sessionRuntimeError:]): 33 (-[WebCoreAVMediaCaptureSourceObserver beginSessionInterrupted:]): 34 (-[WebCoreAVMediaCaptureSourceObserver endSessionInterrupted:]): 35 36 * platform/mediastream/mac/AVVideoCaptureSource.mm: 37 (WebCore::AVVideoCaptureSource::initializeCapabilities): Not all AVCaptureSession preset strings 38 are available on all platforms so load with SOFT_LINK_POINTER_OPTIONAL and NULL check before use. 39 (WebCore::sizeForPreset): Ditto. 40 (WebCore::AVVideoCaptureSource::bestSessionPresetForVideoDimensions): Ditto. 41 1 42 2017-02-22 Zalan Bujtas <zalan@apple.com> 2 43 -
trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.h
r210621 r212844 40 40 OBJC_CLASS AVCaptureSession; 41 41 OBJC_CLASS AVCaptureVideoDataOutput; 42 OBJC_CLASS NSError; 42 43 OBJC_CLASS WebCoreAVMediaCaptureSourceObserver; 43 44 … … 54 55 virtual void captureOutputDidOutputSampleBufferFromConnection(AVCaptureOutput*, CMSampleBufferRef, AVCaptureConnection*) = 0; 55 56 56 virtual void captureSessionIsRunningDidChange(bool); 57 void captureSessionIsRunningDidChange(bool); 58 void captureSessionRuntimeError(RetainPtr<NSError>); 59 60 enum class InterruptionReason { None, VideoNotAllowedInBackground, AudioInUse, VideoInUse, VideoNotAllowedInSideBySide }; 61 void captureSessionBeginInterruption(RetainPtr<NSNotification>); 62 void captureSessionEndInterruption(RetainPtr<NSNotification>); 57 63 58 64 AVCaptureSession *session() const { return m_session.get(); } … … 99 105 RetainPtr<AVCaptureSession> m_session; 100 106 RetainPtr<AVCaptureDevice> m_device; 101 bool m_isRunning { false}; 107 InterruptionReason m_interruption { InterruptionReason::None }; 108 bool m_isRunning { false }; 102 109 }; 103 110 -
trunk/Source/WebCore/platform/mediastream/mac/AVMediaCaptureSource.mm
r211761 r212844 39 39 #import <AVFoundation/AVCaptureOutput.h> 40 40 #import <AVFoundation/AVCaptureSession.h> 41 #import <AVFoundation/AVError.h> 41 42 #import <objc/runtime.h> 42 43 #import <wtf/MainThread.h> … … 73 74 SOFT_LINK_POINTER(AVFoundation, AVMediaTypeMuxed, NSString *) 74 75 SOFT_LINK_POINTER(AVFoundation, AVMediaTypeVideo, NSString *) 75 SOFT_LINK_POINTER(AVFoundation, AVCaptureSessionPreset1280x720, NSString *)76 SOFT_LINK_POINTER(AVFoundation, AVCaptureSessionPreset640x480, NSString *)77 SOFT_LINK_POINTER(AVFoundation, AVCaptureSessionPreset352x288, NSString *)78 SOFT_LINK_POINTER(AVFoundation, AVCaptureSessionPresetLow, NSString *)79 SOFT_LINK_POINTER(AVFoundation, AVCaptureSessionDidStopRunningNotification, NSString *)80 76 81 77 #define AVMediaTypeAudio getAVMediaTypeAudio() 82 78 #define AVMediaTypeMuxed getAVMediaTypeMuxed() 83 79 #define AVMediaTypeVideo getAVMediaTypeVideo() 84 #define AVCaptureSessionPreset1280x720 getAVCaptureSessionPreset1280x720() 85 #define AVCaptureSessionPreset640x480 getAVCaptureSessionPreset640x480() 86 #define AVCaptureSessionPreset352x288 getAVCaptureSessionPreset352x288() 87 #define AVCaptureSessionPresetLow getAVCaptureSessionPresetLow() 88 #define AVCaptureSessionDidStopRunningNotification getAVCaptureSessionDidStopRunningNotification() 80 81 #if PLATFORM(IOS) 82 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionRuntimeErrorNotification, NSString *) 83 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionWasInterruptedNotification, NSString *) 84 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionInterruptionEndedNotification, NSString *) 85 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionInterruptionReasonKey, NSString *) 86 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionErrorKey, NSString *) 87 88 #define AVCaptureSessionRuntimeErrorNotification getAVCaptureSessionRuntimeErrorNotification() 89 #define AVCaptureSessionWasInterruptedNotification getAVCaptureSessionWasInterruptedNotification() 90 #define AVCaptureSessionInterruptionEndedNotification getAVCaptureSessionInterruptionEndedNotification() 91 #define AVCaptureSessionInterruptionReasonKey getAVCaptureSessionInterruptionReasonKey() 92 #define AVCaptureSessionErrorKey getAVCaptureSessionErrorKey() 93 #endif 89 94 90 95 using namespace WebCore; … … 97 102 -(id)initWithCallback:(AVMediaCaptureSource*)callback; 98 103 -(void)disconnect; 99 -(void)captureOutput:(AVCaptureOutputType *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnectionType *)connection; 100 -(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context; 104 -(void)addNotificationObservers; 105 -(void)removeNotificationObservers; 106 -(void)captureOutput:(AVCaptureOutputType*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnectionType*)connection; 107 -(void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context; 108 #if PLATFORM(IOS) 109 -(void)sessionRuntimeError:(NSNotification*)notification; 110 -(void)beginSessionInterrupted:(NSNotification*)notification; 111 -(void)endSessionInterrupted:(NSNotification*)notification; 112 #endif 101 113 @end 102 114 103 115 namespace WebCore { 104 116 105 static NSArray * sessionKVOProperties();117 static NSArray<NSString*>* sessionKVOProperties(); 106 118 107 119 static dispatch_queue_t globaAudioCaptureSerialQueue() … … 131 143 , m_device(device) 132 144 { 145 #if PLATFORM(IOS) 146 static_assert(static_cast<int>(InterruptionReason::VideoNotAllowedInBackground) == static_cast<int>(AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableInBackground), "InterruptionReason::VideoNotAllowedInBackground is not AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableInBackground as expected"); 147 static_assert(static_cast<int>(InterruptionReason::VideoNotAllowedInSideBySide) == AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps, "InterruptionReason::VideoNotAllowedInSideBySide is not AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps as expected"); 148 static_assert(static_cast<int>(InterruptionReason::VideoInUse) == AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient, "InterruptionReason::VideoInUse is not AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient as expected"); 149 static_assert(static_cast<int>(InterruptionReason::AudioInUse) == AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient, "InterruptionReason::AudioInUse is not AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient as expected"); 150 #endif 151 133 152 setPersistentID(device.uniqueID); 134 153 setMuted(true); … … 139 158 [m_objcObserver disconnect]; 140 159 141 if (m_session) { 142 for (NSString *keyName in sessionKVOProperties()) 143 [m_session removeObserver:m_objcObserver.get() forKeyPath:keyName]; 160 if (!m_session) 161 return; 162 163 for (NSString *keyName in sessionKVOProperties()) 164 [m_session removeObserver:m_objcObserver.get() forKeyPath:keyName]; 165 166 if ([m_session isRunning]) 144 167 [m_session stopRunning]; 145 } 168 146 169 } 147 170 … … 153 176 if ([m_session isRunning]) 154 177 return; 155 178 179 [m_objcObserver addNotificationObservers]; 156 180 [m_session startRunning]; 157 181 } … … 162 186 return; 163 187 188 [m_objcObserver removeNotificationObservers]; 164 189 [m_session stopRunning]; 165 190 } … … 224 249 225 250 m_session = adoptNS([allocAVCaptureSessionInstance() init]); 226 for (NSString *keyName in sessionKVOProperties())251 for (NSString* keyName in sessionKVOProperties()) 227 252 [m_session addObserver:m_objcObserver.get() forKeyPath:keyName options:NSKeyValueObservingOptionNew context:(void *)nil]; 228 253 … … 254 279 } 255 280 281 #if PLATFORM(IOS) 282 void AVMediaCaptureSource::captureSessionRuntimeError(RetainPtr<NSError> error) 283 { 284 if (!m_isRunning || error.get().code != AVErrorMediaServicesWereReset) 285 return; 286 287 // Try to restart the session, but reset m_isRunning immediately so if it fails we won't try again. 288 [m_session startRunning]; 289 m_isRunning = [m_session isRunning]; 290 } 291 292 void AVMediaCaptureSource::captureSessionBeginInterruption(RetainPtr<NSNotification> notification) 293 { 294 m_interruption = static_cast<AVMediaCaptureSource::InterruptionReason>([notification.get().userInfo[AVCaptureSessionInterruptionReasonKey] integerValue]); 295 } 296 297 void AVMediaCaptureSource::captureSessionEndInterruption(RetainPtr<NSNotification>) 298 { 299 InterruptionReason reason = m_interruption; 300 301 m_interruption = InterruptionReason::None; 302 if (reason != InterruptionReason::VideoNotAllowedInSideBySide || m_isRunning) 303 return; 304 305 [m_session startRunning]; 306 m_isRunning = [m_session isRunning]; 307 } 308 #endif 309 256 310 void AVMediaCaptureSource::setVideoSampleBufferDelegate(AVCaptureVideoDataOutputType* videoOutput) 257 311 { … … 270 324 } 271 325 272 NSArray * sessionKVOProperties()326 NSArray<NSString*>* sessionKVOProperties() 273 327 { 274 328 static NSArray* keys = [@[@"running"] retain]; … … 287 341 288 342 m_callback = callback; 343 289 344 return self; 290 345 } … … 294 349 [NSObject cancelPreviousPerformRequestsWithTarget:self]; 295 350 m_callback = 0; 296 } 297 298 - (void)captureOutput:(AVCaptureOutputType *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnectionType *)connection 351 [self removeNotificationObservers]; 352 } 353 354 - (void)addNotificationObservers 355 { 356 #if PLATFORM(IOS) 357 ASSERT(m_callback); 358 359 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 360 AVCaptureSessionType* session = m_callback->session(); 361 362 [center addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:session]; 363 [center addObserver:self selector:@selector(beginSessionInterrupted:) name:AVCaptureSessionWasInterruptedNotification object:session]; 364 [center addObserver:self selector:@selector(endSessionInterrupted:) name:AVCaptureSessionInterruptionEndedNotification object:session]; 365 #endif 366 } 367 368 - (void)removeNotificationObservers 369 { 370 #if PLATFORM(IOS) 371 ASSERT(m_callback); 372 [[NSNotificationCenter defaultCenter] removeObserver:m_callback->session()]; 373 #endif 374 } 375 376 - (void)captureOutput:(AVCaptureOutputType*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnectionType*)connection 299 377 { 300 378 if (!m_callback) … … 304 382 } 305 383 306 - (void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context384 - (void)observeValueForKeyPath:keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context 307 385 { 308 386 UNUSED_PARAM(object); … … 329 407 } 330 408 409 #if PLATFORM(IOS) 410 - (void)sessionRuntimeError:(NSNotification*)notification 411 { 412 NSError *error = notification.userInfo[AVCaptureSessionErrorKey]; 413 LOG(Media, "WebCoreAVMediaCaptureSourceObserver::sessionRuntimeError(%p) - error = %s", self, [[error localizedDescription] UTF8String]); 414 415 if (m_callback) 416 m_callback->captureSessionRuntimeError(error); 417 } 418 419 -(void)beginSessionInterrupted:(NSNotification*)notification 420 { 421 LOG(Media, "WebCoreAVMediaCaptureSourceObserver::beginSessionInterrupted(%p) - reason = %d", self, [notification.userInfo[AVCaptureSessionInterruptionReasonKey] integerValue]); 422 423 if (m_callback) 424 m_callback->captureSessionBeginInterruption(notification); 425 } 426 427 - (void)endSessionInterrupted:(NSNotification*)notification 428 { 429 LOG(Media, "WebCoreAVMediaCaptureSourceObserver::endSessionInterrupted(%p) ", self); 430 431 if (m_callback) 432 m_callback->captureSessionEndInterruption(notification); 433 } 434 #endif 435 331 436 @end 332 437 -
trunk/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
r211728 r212844 85 85 #define AVFrameRateRange getAVFrameRateRangeClass() 86 86 87 SOFT_LINK_POINTER (AVFoundation, AVCaptureSessionPreset1280x720, NSString *)88 SOFT_LINK_POINTER (AVFoundation, AVCaptureSessionPreset960x540, NSString *)89 SOFT_LINK_POINTER (AVFoundation, AVCaptureSessionPreset640x480, NSString *)90 SOFT_LINK_POINTER (AVFoundation, AVCaptureSessionPreset352x288, NSString *)91 SOFT_LINK_POINTER (AVFoundation, AVCaptureSessionPreset320x240, NSString *)92 SOFT_LINK_POINTER (AVFoundation, AVCaptureSessionPresetLow, NSString *)87 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionPreset1280x720, NSString *) 88 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionPreset960x540, NSString *) 89 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionPreset640x480, NSString *) 90 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionPreset352x288, NSString *) 91 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionPreset320x240, NSString *) 92 SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVCaptureSessionPresetLow, NSString *) 93 93 94 94 #define AVCaptureSessionPreset1280x720 getAVCaptureSessionPreset1280x720() … … 165 165 } 166 166 167 if ( [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset1280x720]) {167 if (AVCaptureSessionPreset1280x720 && [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset1280x720]) { 168 168 updateSizeMinMax(minimumWidth, maximumWidth, 1280); 169 169 updateSizeMinMax(minimumHeight, maximumHeight, 720); 170 170 updateAspectRatioMinMax(minimumAspectRatio, maximumAspectRatio, 1280.0 / 720); 171 171 } 172 if ( [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset960x540]) {172 if (AVCaptureSessionPreset960x540 && [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset960x540]) { 173 173 updateSizeMinMax(minimumWidth, maximumWidth, 960); 174 174 updateSizeMinMax(minimumHeight, maximumHeight, 540); 175 175 updateAspectRatioMinMax(minimumAspectRatio, maximumAspectRatio, 960 / 540); 176 176 } 177 if ( [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]) {177 if (AVCaptureSessionPreset640x480 && [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]) { 178 178 updateSizeMinMax(minimumWidth, maximumWidth, 640); 179 179 updateSizeMinMax(minimumHeight, maximumHeight, 480); 180 180 updateAspectRatioMinMax(minimumAspectRatio, maximumAspectRatio, 640 / 480); 181 181 } 182 if ( [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset352x288]) {182 if (AVCaptureSessionPreset352x288 && [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset352x288]) { 183 183 updateSizeMinMax(minimumWidth, maximumWidth, 352); 184 184 updateSizeMinMax(minimumHeight, maximumHeight, 288); 185 185 updateAspectRatioMinMax(minimumAspectRatio, maximumAspectRatio, 352 / 288); 186 186 } 187 if ( [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset320x240]) {187 if (AVCaptureSessionPreset320x240 && [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset320x240]) { 188 188 updateSizeMinMax(minimumWidth, maximumWidth, 320); 189 189 updateSizeMinMax(minimumHeight, maximumHeight, 240); … … 240 240 return { }; 241 241 242 if ( [preset isEqualToString:AVCaptureSessionPreset1280x720])242 if (AVCaptureSessionPreset1280x720 && [preset isEqualToString:AVCaptureSessionPreset1280x720]) 243 243 return { 1280, 720 }; 244 244 245 if ( [preset isEqualToString:AVCaptureSessionPreset960x540])245 if (AVCaptureSessionPreset960x540 && [preset isEqualToString:AVCaptureSessionPreset960x540]) 246 246 return { 960, 540 }; 247 247 248 if ( [preset isEqualToString:AVCaptureSessionPreset640x480])248 if (AVCaptureSessionPreset640x480 && [preset isEqualToString:AVCaptureSessionPreset640x480]) 249 249 return { 640, 480 }; 250 250 251 if ( [preset isEqualToString:AVCaptureSessionPreset352x288])251 if (AVCaptureSessionPreset352x288 && [preset isEqualToString:AVCaptureSessionPreset352x288]) 252 252 return { 352, 288 }; 253 253 254 if ( [preset isEqualToString:AVCaptureSessionPreset320x240])254 if (AVCaptureSessionPreset320x240 && [preset isEqualToString:AVCaptureSessionPreset320x240]) 255 255 return { 320, 240 }; 256 256 … … 496 496 497 497 AVCaptureDeviceTypedef *videoDevice = device(); 498 if ((!width || width.value() == 1280) && (!height || height.value() == 720) )498 if ((!width || width.value() == 1280) && (!height || height.value() == 720) && AVCaptureSessionPreset1280x720) 499 499 return [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset1280x720] ? AVCaptureSessionPreset1280x720 : nil; 500 500 501 if ((!width || width.value() == 960) && (!height || height.value() == 540 ))501 if ((!width || width.value() == 960) && (!height || height.value() == 540) && AVCaptureSessionPreset960x540) 502 502 return [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset960x540] ? AVCaptureSessionPreset960x540 : nil; 503 503 504 if ((!width || width.value() == 640) && (!height || height.value() == 480 ) )504 if ((!width || width.value() == 640) && (!height || height.value() == 480 ) && AVCaptureSessionPreset640x480) 505 505 return [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480] ? AVCaptureSessionPreset640x480 : nil; 506 506 507 if ((!width || width.value() == 352) && (!height || height.value() == 288 ) )507 if ((!width || width.value() == 352) && (!height || height.value() == 288 ) && AVCaptureSessionPreset352x288) 508 508 return [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset352x288] ? AVCaptureSessionPreset352x288 : nil; 509 509 510 if ((!width || width.value() == 320) && (!height || height.value() == 240 ) )510 if ((!width || width.value() == 320) && (!height || height.value() == 240 ) && AVCaptureSessionPreset320x240) 511 511 return [videoDevice supportsAVCaptureSessionPreset:AVCaptureSessionPreset320x240] ? AVCaptureSessionPreset320x240 : nil; 512 512
Note:
See TracChangeset
for help on using the changeset viewer.