Changeset 271245 in webkit
- Timestamp:
- Jan 7, 2021, 11:49:38 AM (6 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 12 edited
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/html/HTMLMediaElement.cpp (modified) (3 diffs)
-
Source/WebCore/html/HTMLMediaElement.h (modified) (1 diff)
-
Source/WebCore/platform/graphics/MediaPlayer.cpp (modified) (2 diffs)
-
Source/WebCore/platform/graphics/MediaPlayer.h (modified) (1 diff)
-
Source/WebKit/ChangeLog (modified) (1 diff)
-
Source/WebKit/WebProcess/GPU/GPUProcessConnection.h (modified) (2 diffs)
-
Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.cpp (modified) (4 diffs)
-
Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.h (modified) (2 diffs)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (modified) (4 diffs)
-
Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r271239 r271245 1 2021-01-07 Chris Dumez <cdumez@apple.com> 2 3 [GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode 4 https://bugs.webkit.org/show_bug.cgi?id=220391 5 6 Reviewed by Geoffrey Garen. 7 8 When audio is playing using WebAudio and a MediaElementAudioSourceNode, make sure that 9 audio resumes playing seemlessly after a GPUProcess crash. 10 11 * html/HTMLMediaElement.cpp: 12 (WebCore::HTMLMediaElement::mediaEngineWasUpdated): 13 (WebCore::HTMLMediaElement::mediaPlayerEngineUpdated): 14 Reconstruct the audioSourceProvider (and add the audioSourceNode as its client) as soon 15 as possible after the media engine was (re-)initialized in mediaPlayerEngineUpdated(), 16 instead of doing it asynchronously in mediaEngineWasUpdated(). This does not run script 17 so it is safe to call synchronously. If the GPUProcess crashes while a 18 MediaElementAudioSourceNode is playing, MediaElementAudioSourceNode::process() needs the 19 audioSourceProvider to get the input audio. If we don't eagerly construct the 20 audioSourceProvider here, then it may happen on the audio rendering thread, when the 21 MediaElementAudioSourceNode actually needs it, which would not be safe. 22 23 (WebCore::HTMLMediaElement::mediaPlayerWillInitializeMediaEngine): 24 (WebCore::HTMLMediaElement::mediaPlayerDidInitializeMediaEngine): 25 As mentioned earlier, MediaElementAudioSourceNode::process() runs on the audio thread 26 and accesses HTMLMediaElement::audioSourceProvider(), which calls 27 MediaPlayer::audioSourceProvider(), which calls 28 MediaPlayerPrivate::audioSourceProvider(). To be thread-safe, we need to make sure we 29 hold the MediaElementAudioSourceNode's process lock while the MediaPlayerPrivate is 30 being reconstructed in MediaPlayer (which happens when the GPUProcess crashes). 31 32 * html/HTMLMediaElement.h: 33 * platform/graphics/MediaPlayer.cpp: 34 (WebCore::MediaPlayer::loadWithNextMediaEngine): 35 * platform/graphics/MediaPlayer.h: 36 (WebCore::MediaPlayerClient::mediaPlayerWillInitializeMediaEngine): 37 (WebCore::MediaPlayerClient::mediaPlayerDidInitializeMediaEngine): 38 Add new MediaPlayerClient interface functions that are called before and after the 39 MediaPlayerPrivate gets (re-)constructed. This is needed by the HTMLMediaElement 40 to hold a lock while this is happening. 41 1 42 2021-01-07 Alex Christensen <achristensen@webkit.org> 2 43 -
trunk/Source/WebCore/html/HTMLMediaElement.cpp
r271219 r271245 4967 4967 m_mediaSession->mediaEngineUpdated(); 4968 4968 4969 #if ENABLE(WEB_AUDIO)4970 if (m_audioSourceNode && audioSourceProvider()) {4971 auto locker = holdLock(m_audioSourceNode->processLock());4972 audioSourceProvider()->setClient(m_audioSourceNode);4973 }4974 #endif4975 4976 4969 #if ENABLE(ENCRYPTED_MEDIA) 4977 4970 if (m_player && m_mediaKeys) … … 5012 5005 #endif 5013 5006 5007 #if ENABLE(WEB_AUDIO) 5008 if (m_audioSourceNode) { 5009 if (auto* provider = audioSourceProvider()) 5010 provider->setClient(m_audioSourceNode); 5011 } 5012 #endif 5013 5014 5014 m_havePreparedToPlay = false; 5015 5015 5016 5016 scheduleMediaEngineWasUpdated(); 5017 } 5018 5019 void HTMLMediaElement::mediaPlayerWillInitializeMediaEngine() 5020 { 5021 ASSERT(isMainThread()); 5022 #if ENABLE(WEB_AUDIO) 5023 // Make sure the MediaElementAudioSourceNode's process function does not try and access the media player while its engine is getting updated. 5024 if (m_audioSourceNode) 5025 m_audioSourceNode->processLock().lock(); 5026 #endif 5027 } 5028 5029 void HTMLMediaElement::mediaPlayerDidInitializeMediaEngine() 5030 { 5031 ASSERT(isMainThread()); 5032 #if ENABLE(WEB_AUDIO) 5033 if (m_audioSourceNode) 5034 m_audioSourceNode->processLock().unlock(); 5035 #endif 5017 5036 } 5018 5037 … … 6561 6580 } 6562 6581 6582 // This may get called on the audio thread by MediaElementAudioSourceNode. 6563 6583 AudioSourceProvider* HTMLMediaElement::audioSourceProvider() 6564 6584 { -
trunk/Source/WebCore/html/HTMLMediaElement.h
r270171 r271245 659 659 bool mediaPlayerAcceleratedCompositingEnabled() final; 660 660 void mediaPlayerEngineUpdated() final; 661 void mediaPlayerWillInitializeMediaEngine() final; 662 void mediaPlayerDidInitializeMediaEngine() final; 661 663 662 664 void scheduleMediaEngineWasUpdated(); -
trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp
r271219 r271245 562 562 ASSERT(!m_initializingMediaEngine); 563 563 m_initializingMediaEngine = true; 564 client().mediaPlayerWillInitializeMediaEngine(); 564 565 565 566 const MediaPlayerFactory* engine = nullptr; … … 611 612 612 613 m_initializingMediaEngine = false; 614 client().mediaPlayerDidInitializeMediaEngine(); 613 615 } 614 616 -
trunk/Source/WebCore/platform/graphics/MediaPlayer.h
r271219 r271245 212 212 #endif 213 213 214 virtual void mediaPlayerWillInitializeMediaEngine() { } 215 virtual void mediaPlayerDidInitializeMediaEngine() { } 216 214 217 virtual String mediaPlayerReferrer() const { return String(); } 215 218 virtual String mediaPlayerUserAgent() const { return String(); } -
trunk/Source/WebKit/ChangeLog
r271243 r271245 1 2021-01-07 Chris Dumez <cdumez@apple.com> 2 3 [GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode 4 https://bugs.webkit.org/show_bug.cgi?id=220391 5 6 Reviewed by Geoffrey Garen. 7 8 When audio is playing using WebAudio and a MediaElementAudioSourceNode, make sure that 9 audio resumes playing seemlessly after a GPUProcess crash. 10 11 * WebProcess/GPU/GPUProcessConnection.h: 12 Subclass CanMakeWeakPtr<> so that clients can hold a weak pointer to a GPUProcessConnection. 13 14 * WebProcess/GPU/media/RemoteAudioSourceProvider.cpp: 15 (WebKit::RemoteAudioSourceProvider::create): 16 (WebKit::RemoteAudioSourceProvider::RemoteAudioSourceProvider): 17 (WebKit::RemoteAudioSourceProvider::close): 18 (WebKit::RemoteAudioSourceProvider::hasNewClient): 19 * WebProcess/GPU/media/RemoteAudioSourceProvider.h: 20 Associate the RemoteAudioSourceProvider with a specific GPUProcessConnection instead of always 21 using the latest connection via WebProcess::ensureGPUProcessConnection(). In the event of a 22 GPUProcess crash, MediaPlayer will reconstruct its MediaPlayerPrivate which will reconstruct 23 a new RemoteAudioSourceProvider (since RemoteAudioSourceProvider is owned by 24 MediaPlayerPrivateRemote). As a result, RemoteAudioSourceProvider does not need to do anything 25 to deal with a GPUProcess crash. However, we need to make sure it only interacts with the 26 GPUProcessConnection that existed when it was constructed. 27 1 28 2021-01-07 Kimmo Kinnunen <kkinnunen@apple.com> 2 29 -
trunk/Source/WebKit/WebProcess/GPU/GPUProcessConnection.h
r270720 r271245 34 34 #include <wtf/RefCounted.h> 35 35 #include <wtf/WeakHashSet.h> 36 #include <wtf/WeakPtr.h> 36 37 #include <wtf/text/WTFString.h> 37 38 … … 45 46 struct WebPageCreationParameters; 46 47 47 class GPUProcessConnection : public RefCounted<GPUProcessConnection>, IPC::Connection::Client {48 class GPUProcessConnection : public RefCounted<GPUProcessConnection>, public CanMakeWeakPtr<GPUProcessConnection>, IPC::Connection::Client { 48 49 public: 49 50 static Ref<GPUProcessConnection> create(IPC::Connection::Identifier connectionIdentifier) -
trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.cpp
r270573 r271245 45 45 { 46 46 auto provider = adoptRef(*new RemoteAudioSourceProvider(identifier, helper)); 47 48 auto& gpuProcessConnection = WebProcess::singleton().ensureGPUProcessConnection(); 49 gpuProcessConnection.audioSourceProviderManager().addProvider(provider.copyRef()); 50 51 #if ENABLE(WEB_AUDIO) 52 gpuProcessConnection.connection().send(Messages::RemoteMediaPlayerProxy::CreateAudioSourceProvider { }, provider->identifier()); 53 #endif 54 47 provider->m_gpuProcessConnection->audioSourceProviderManager().addProvider(provider.copyRef()); 55 48 return provider; 56 49 } … … 58 51 RemoteAudioSourceProvider::RemoteAudioSourceProvider(MediaPlayerIdentifier identifier, WTF::LoggerHelper& helper) 59 52 : m_identifier(identifier) 53 , m_gpuProcessConnection(makeWeakPtr(WebProcess::singleton().ensureGPUProcessConnection())) 60 54 #if !RELEASE_LOG_DISABLED 61 55 , m_logger(helper.logger()) … … 65 59 ASSERT(isMainThread()); 66 60 UNUSED_PARAM(helper); 61 62 #if ENABLE(WEB_AUDIO) 63 m_gpuProcessConnection->connection().send(Messages::RemoteMediaPlayerProxy::CreateAudioSourceProvider { }, identifier); 64 #endif 67 65 } 68 66 … … 74 72 { 75 73 ASSERT(isMainThread()); 76 WebProcess::singleton().ensureGPUProcessConnection().audioSourceProviderManager().removeProvider(m_identifier); 74 if (m_gpuProcessConnection) 75 m_gpuProcessConnection->audioSourceProviderManager().removeProvider(m_identifier); 77 76 } 78 77 79 78 void RemoteAudioSourceProvider::hasNewClient(AudioSourceProviderClient* client) 80 79 { 81 WebProcess::singleton().ensureGPUProcessConnection().connection().send(Messages::RemoteMediaPlayerProxy::SetShouldEnableAudioSourceProvider { !!client }, m_identifier); 80 if (m_gpuProcessConnection) 81 m_gpuProcessConnection->connection().send(Messages::RemoteMediaPlayerProxy::SetShouldEnableAudioSourceProvider { !!client }, m_identifier); 82 82 } 83 83 -
trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.h
r268521 r271245 28 28 #if ENABLE(GPU_PROCESS) && ENABLE(WEB_AUDIO) && PLATFORM(COCOA) 29 29 30 #include "GPUProcessConnection.h" 30 31 #include <WebCore/MediaPlayerIdentifier.h> 31 32 #include <WebCore/WebAudioSourceProviderCocoa.h> … … 66 67 67 68 WebCore::MediaPlayerIdentifier m_identifier; 69 WeakPtr<GPUProcessConnection> m_gpuProcessConnection; 68 70 #if !RELEASE_LOG_DISABLED 69 71 Ref<const Logger> m_logger; -
trunk/Tools/ChangeLog
r271244 r271245 1 2021-01-07 Chris Dumez <cdumez@apple.com> 2 3 [GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode 4 https://bugs.webkit.org/show_bug.cgi?id=220391 5 6 Reviewed by Geoffrey Garen. 7 8 Add API test coverage. 9 10 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: 11 * TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm: 12 (TEST): 13 * TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html: Added. 14 1 15 2021-01-07 Sam Sneddon <gsnedders@apple.com> 2 16 -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
r271190 r271245 260 260 468F2F942368DAF100F4B864 /* window-open-then-document-open.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 468F2F932368DAA700F4B864 /* window-open-then-document-open.html */; }; 261 261 46918EFC2237283C00468DFE /* DeviceOrientation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46918EFB2237283500468DFE /* DeviceOrientation.mm */; }; 262 46A44A5425A7830300F61E16 /* webaudio-createMediaElementSource.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */; }; 262 263 46A46A1A2575645600A1B118 /* SessionStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A46A192575645600A1B118 /* SessionStorage.mm */; }; 263 264 46A911592108E6780078D40D /* CustomUserAgent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A911582108E66B0078D40D /* CustomUserAgent.mm */; }; … … 1686 1687 57EDFC5C245A1A3F00959521 /* web-authentication-make-credential-la-no-mock.html in Copy Resources */, 1687 1688 5742178E2400D2DF002B303D /* web-authentication-make-credential-la.html in Copy Resources */, 1689 46A44A5425A7830300F61E16 /* webaudio-createMediaElementSource.html in Copy Resources */, 1688 1690 1C2B81861C89259D00A5529F /* webfont.html in Copy Resources */, 1689 1691 31E9BDA3247F5729002E51A2 /* webgl.html in Copy Resources */, … … 2000 2002 468F2F932368DAA700F4B864 /* window-open-then-document-open.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "window-open-then-document-open.html"; sourceTree = "<group>"; }; 2001 2003 46918EFB2237283500468DFE /* DeviceOrientation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DeviceOrientation.mm; sourceTree = "<group>"; }; 2004 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "webaudio-createMediaElementSource.html"; sourceTree = "<group>"; }; 2002 2005 46A46A192575645600A1B118 /* SessionStorage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SessionStorage.mm; sourceTree = "<group>"; }; 2003 2006 46A911582108E66B0078D40D /* CustomUserAgent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CustomUserAgent.mm; sourceTree = "<group>"; }; … … 3984 3987 57EDFC5B245A18F500959521 /* web-authentication-make-credential-la-no-mock.html */, 3985 3988 5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */, 3989 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */, 3986 3990 51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */, 3987 3991 51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */, -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm
r270628 r271245 292 292 } 293 293 294 TEST(GPUProcess, CrashWhilePlayingAudioViaCreateMediaElementSource) 295 { 296 auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); 297 for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) { 298 if ([feature.key isEqualToString:@"UseGPUProcessForMediaEnabled"]) { 299 [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature]; 300 break; 301 } 302 } 303 304 auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]); 305 [webView synchronouslyLoadTestPageNamed:@"webaudio-createMediaElementSource"]; 306 307 __block bool done = false; 308 [webView evaluateJavaScript:@"document.getElementById('testButton').click()" completionHandler:^(id result, NSError *error) { 309 EXPECT_TRUE(!error); 310 done = true; 311 }]; 312 TestWebKitAPI::Util::run(&done); 313 314 auto webViewPID = [webView _webProcessIdentifier]; 315 316 // The GPU process should get launched. 317 auto* processPool = configuration.get().processPool; 318 unsigned timeout = 0; 319 while (![processPool _gpuProcessIdentifier] && timeout++ < 100) 320 TestWebKitAPI::Util::sleep(0.1); 321 322 EXPECT_NE([processPool _gpuProcessIdentifier], 0); 323 if (![processPool _gpuProcessIdentifier]) 324 return; 325 auto gpuProcessPID = [processPool _gpuProcessIdentifier]; 326 327 // Audio should be playing. 328 timeout = 0; 329 while (![webView _isPlayingAudio] && timeout++ < 100) 330 TestWebKitAPI::Util::sleep(0.1); 331 EXPECT_TRUE([webView _isPlayingAudio]); 332 333 // Kill the GPU Process. 334 kill(gpuProcessPID, 9); 335 336 // GPU Process should get relaunched. 337 timeout = 0; 338 while ((![processPool _gpuProcessIdentifier] || [processPool _gpuProcessIdentifier] == gpuProcessPID) && timeout++ < 100) 339 TestWebKitAPI::Util::sleep(0.1); 340 EXPECT_NE([processPool _gpuProcessIdentifier], 0); 341 EXPECT_NE([processPool _gpuProcessIdentifier], gpuProcessPID); 342 gpuProcessPID = [processPool _gpuProcessIdentifier]; 343 344 // Make sure the WebProcess did not crash. 345 EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]); 346 347 // FIXME: On iOS, video resumes after the GPU process crash but audio does not. 348 #if !PLATFORM(IOS) 349 // Audio should resume playing. 350 timeout = 0; 351 while (![webView _isPlayingAudio] && timeout++ < 100) 352 TestWebKitAPI::Util::sleep(0.1); 353 EXPECT_TRUE([webView _isPlayingAudio]); 354 #endif 355 356 EXPECT_EQ(gpuProcessPID, [processPool _gpuProcessIdentifier]); 357 EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]); 358 } 359 294 360 static NSString *testCanvasPage = @"<body> \n" 295 361 "<canvas id='myCanvas' width='400px' height='400px'>\n"
Note:
See TracChangeset
for help on using the changeset viewer.