- Revision
- 271245
- Author
- [email protected]
- Date
- 2021-01-07 11:49:38 -0800 (Thu, 07 Jan 2021)
Log Message
[GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode
https://bugs.webkit.org/show_bug.cgi?id=220391
Reviewed by Geoffrey Garen.
Source/WebCore:
When audio is playing using WebAudio and a MediaElementAudioSourceNode, make sure that
audio resumes playing seemlessly after a GPUProcess crash.
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::mediaEngineWasUpdated):
(WebCore::HTMLMediaElement::mediaPlayerEngineUpdated):
Reconstruct the audioSourceProvider (and add the audioSourceNode as its client) as soon
as possible after the media engine was (re-)initialized in mediaPlayerEngineUpdated(),
instead of doing it asynchronously in mediaEngineWasUpdated(). This does not run script
so it is safe to call synchronously. If the GPUProcess crashes while a
MediaElementAudioSourceNode is playing, MediaElementAudioSourceNode::process() needs the
audioSourceProvider to get the input audio. If we don't eagerly construct the
audioSourceProvider here, then it may happen on the audio rendering thread, when the
MediaElementAudioSourceNode actually needs it, which would not be safe.
(WebCore::HTMLMediaElement::mediaPlayerWillInitializeMediaEngine):
(WebCore::HTMLMediaElement::mediaPlayerDidInitializeMediaEngine):
As mentioned earlier, MediaElementAudioSourceNode::process() runs on the audio thread
and accesses HTMLMediaElement::audioSourceProvider(), which calls
MediaPlayer::audioSourceProvider(), which calls
MediaPlayerPrivate::audioSourceProvider(). To be thread-safe, we need to make sure we
hold the MediaElementAudioSourceNode's process lock while the MediaPlayerPrivate is
being reconstructed in MediaPlayer (which happens when the GPUProcess crashes).
* html/HTMLMediaElement.h:
* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::loadWithNextMediaEngine):
* platform/graphics/MediaPlayer.h:
(WebCore::MediaPlayerClient::mediaPlayerWillInitializeMediaEngine):
(WebCore::MediaPlayerClient::mediaPlayerDidInitializeMediaEngine):
Add new MediaPlayerClient interface functions that are called before and after the
MediaPlayerPrivate gets (re-)constructed. This is needed by the HTMLMediaElement
to hold a lock while this is happening.
Source/WebKit:
When audio is playing using WebAudio and a MediaElementAudioSourceNode, make sure that
audio resumes playing seemlessly after a GPUProcess crash.
* WebProcess/GPU/GPUProcessConnection.h:
Subclass CanMakeWeakPtr<> so that clients can hold a weak pointer to a GPUProcessConnection.
* WebProcess/GPU/media/RemoteAudioSourceProvider.cpp:
(WebKit::RemoteAudioSourceProvider::create):
(WebKit::RemoteAudioSourceProvider::RemoteAudioSourceProvider):
(WebKit::RemoteAudioSourceProvider::close):
(WebKit::RemoteAudioSourceProvider::hasNewClient):
* WebProcess/GPU/media/RemoteAudioSourceProvider.h:
Associate the RemoteAudioSourceProvider with a specific GPUProcessConnection instead of always
using the latest connection via WebProcess::ensureGPUProcessConnection(). In the event of a
GPUProcess crash, MediaPlayer will reconstruct its MediaPlayerPrivate which will reconstruct
a new RemoteAudioSourceProvider (since RemoteAudioSourceProvider is owned by
MediaPlayerPrivateRemote). As a result, RemoteAudioSourceProvider does not need to do anything
to deal with a GPUProcess crash. However, we need to make sure it only interacts with the
GPUProcessConnection that existed when it was constructed.
Tools:
Add API test coverage.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm:
(TEST):
* TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (271244 => 271245)
--- trunk/Source/WebCore/ChangeLog 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebCore/ChangeLog 2021-01-07 19:49:38 UTC (rev 271245)
@@ -1,3 +1,44 @@
+2021-01-07 Chris Dumez <[email protected]>
+
+ [GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode
+ https://bugs.webkit.org/show_bug.cgi?id=220391
+
+ Reviewed by Geoffrey Garen.
+
+ When audio is playing using WebAudio and a MediaElementAudioSourceNode, make sure that
+ audio resumes playing seemlessly after a GPUProcess crash.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::HTMLMediaElement::mediaEngineWasUpdated):
+ (WebCore::HTMLMediaElement::mediaPlayerEngineUpdated):
+ Reconstruct the audioSourceProvider (and add the audioSourceNode as its client) as soon
+ as possible after the media engine was (re-)initialized in mediaPlayerEngineUpdated(),
+ instead of doing it asynchronously in mediaEngineWasUpdated(). This does not run script
+ so it is safe to call synchronously. If the GPUProcess crashes while a
+ MediaElementAudioSourceNode is playing, MediaElementAudioSourceNode::process() needs the
+ audioSourceProvider to get the input audio. If we don't eagerly construct the
+ audioSourceProvider here, then it may happen on the audio rendering thread, when the
+ MediaElementAudioSourceNode actually needs it, which would not be safe.
+
+ (WebCore::HTMLMediaElement::mediaPlayerWillInitializeMediaEngine):
+ (WebCore::HTMLMediaElement::mediaPlayerDidInitializeMediaEngine):
+ As mentioned earlier, MediaElementAudioSourceNode::process() runs on the audio thread
+ and accesses HTMLMediaElement::audioSourceProvider(), which calls
+ MediaPlayer::audioSourceProvider(), which calls
+ MediaPlayerPrivate::audioSourceProvider(). To be thread-safe, we need to make sure we
+ hold the MediaElementAudioSourceNode's process lock while the MediaPlayerPrivate is
+ being reconstructed in MediaPlayer (which happens when the GPUProcess crashes).
+
+ * html/HTMLMediaElement.h:
+ * platform/graphics/MediaPlayer.cpp:
+ (WebCore::MediaPlayer::loadWithNextMediaEngine):
+ * platform/graphics/MediaPlayer.h:
+ (WebCore::MediaPlayerClient::mediaPlayerWillInitializeMediaEngine):
+ (WebCore::MediaPlayerClient::mediaPlayerDidInitializeMediaEngine):
+ Add new MediaPlayerClient interface functions that are called before and after the
+ MediaPlayerPrivate gets (re-)constructed. This is needed by the HTMLMediaElement
+ to hold a lock while this is happening.
+
2021-01-07 Alex Christensen <[email protected]>
Null check global object in Blob::stream
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (271244 => 271245)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2021-01-07 19:49:38 UTC (rev 271245)
@@ -4966,13 +4966,6 @@
m_mediaSession->mediaEngineUpdated();
-#if ENABLE(WEB_AUDIO)
- if (m_audioSourceNode && audioSourceProvider()) {
- auto locker = holdLock(m_audioSourceNode->processLock());
- audioSourceProvider()->setClient(m_audioSourceNode);
- }
-#endif
-
#if ENABLE(ENCRYPTED_MEDIA)
if (m_player && m_mediaKeys)
m_player->cdmInstanceAttached(m_mediaKeys->cdmInstance());
@@ -5011,11 +5004,37 @@
m_droppedVideoFrames = 0;
#endif
+#if ENABLE(WEB_AUDIO)
+ if (m_audioSourceNode) {
+ if (auto* provider = audioSourceProvider())
+ provider->setClient(m_audioSourceNode);
+ }
+#endif
+
m_havePreparedToPlay = false;
scheduleMediaEngineWasUpdated();
}
+void HTMLMediaElement::mediaPlayerWillInitializeMediaEngine()
+{
+ ASSERT(isMainThread());
+#if ENABLE(WEB_AUDIO)
+ // Make sure the MediaElementAudioSourceNode's process function does not try and access the media player while its engine is getting updated.
+ if (m_audioSourceNode)
+ m_audioSourceNode->processLock().lock();
+#endif
+}
+
+void HTMLMediaElement::mediaPlayerDidInitializeMediaEngine()
+{
+ ASSERT(isMainThread());
+#if ENABLE(WEB_AUDIO)
+ if (m_audioSourceNode)
+ m_audioSourceNode->processLock().unlock();
+#endif
+}
+
void HTMLMediaElement::mediaPlayerCharacteristicChanged()
{
ALWAYS_LOG(LOGIDENTIFIER);
@@ -6560,6 +6579,7 @@
audioSourceProvider()->setClient(m_audioSourceNode);
}
+// This may get called on the audio thread by MediaElementAudioSourceNode.
AudioSourceProvider* HTMLMediaElement::audioSourceProvider()
{
if (m_player)
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (271244 => 271245)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2021-01-07 19:49:38 UTC (rev 271245)
@@ -658,6 +658,8 @@
void mediaPlayerRenderingModeChanged() final;
bool mediaPlayerAcceleratedCompositingEnabled() final;
void mediaPlayerEngineUpdated() final;
+ void mediaPlayerWillInitializeMediaEngine() final;
+ void mediaPlayerDidInitializeMediaEngine() final;
void scheduleMediaEngineWasUpdated();
void mediaEngineWasUpdated();
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (271244 => 271245)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2021-01-07 19:49:38 UTC (rev 271245)
@@ -561,6 +561,7 @@
ASSERT(!m_initializingMediaEngine);
m_initializingMediaEngine = true;
+ client().mediaPlayerWillInitializeMediaEngine();
const MediaPlayerFactory* engine = nullptr;
@@ -610,6 +611,7 @@
}
m_initializingMediaEngine = false;
+ client().mediaPlayerDidInitializeMediaEngine();
}
bool MediaPlayer::hasAvailableVideoFrame() const
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (271244 => 271245)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2021-01-07 19:49:38 UTC (rev 271245)
@@ -211,6 +211,9 @@
virtual void mediaPlayerCurrentPlaybackTargetIsWirelessChanged(bool) { };
#endif
+ virtual void mediaPlayerWillInitializeMediaEngine() { }
+ virtual void mediaPlayerDidInitializeMediaEngine() { }
+
virtual String mediaPlayerReferrer() const { return String(); }
virtual String mediaPlayerUserAgent() const { return String(); }
virtual void mediaPlayerEnterFullscreen() { }
Modified: trunk/Source/WebKit/ChangeLog (271244 => 271245)
--- trunk/Source/WebKit/ChangeLog 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebKit/ChangeLog 2021-01-07 19:49:38 UTC (rev 271245)
@@ -1,3 +1,30 @@
+2021-01-07 Chris Dumez <[email protected]>
+
+ [GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode
+ https://bugs.webkit.org/show_bug.cgi?id=220391
+
+ Reviewed by Geoffrey Garen.
+
+ When audio is playing using WebAudio and a MediaElementAudioSourceNode, make sure that
+ audio resumes playing seemlessly after a GPUProcess crash.
+
+ * WebProcess/GPU/GPUProcessConnection.h:
+ Subclass CanMakeWeakPtr<> so that clients can hold a weak pointer to a GPUProcessConnection.
+
+ * WebProcess/GPU/media/RemoteAudioSourceProvider.cpp:
+ (WebKit::RemoteAudioSourceProvider::create):
+ (WebKit::RemoteAudioSourceProvider::RemoteAudioSourceProvider):
+ (WebKit::RemoteAudioSourceProvider::close):
+ (WebKit::RemoteAudioSourceProvider::hasNewClient):
+ * WebProcess/GPU/media/RemoteAudioSourceProvider.h:
+ Associate the RemoteAudioSourceProvider with a specific GPUProcessConnection instead of always
+ using the latest connection via WebProcess::ensureGPUProcessConnection(). In the event of a
+ GPUProcess crash, MediaPlayer will reconstruct its MediaPlayerPrivate which will reconstruct
+ a new RemoteAudioSourceProvider (since RemoteAudioSourceProvider is owned by
+ MediaPlayerPrivateRemote). As a result, RemoteAudioSourceProvider does not need to do anything
+ to deal with a GPUProcess crash. However, we need to make sure it only interacts with the
+ GPUProcessConnection that existed when it was constructed.
+
2021-01-07 Kimmo Kinnunen <[email protected]>
WebKit IPC message names should indicate if the message is synchronous
Modified: trunk/Source/WebKit/WebProcess/GPU/GPUProcessConnection.h (271244 => 271245)
--- trunk/Source/WebKit/WebProcess/GPU/GPUProcessConnection.h 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebKit/WebProcess/GPU/GPUProcessConnection.h 2021-01-07 19:49:38 UTC (rev 271245)
@@ -33,6 +33,7 @@
#include <WebCore/PlatformMediaSession.h>
#include <wtf/RefCounted.h>
#include <wtf/WeakHashSet.h>
+#include <wtf/WeakPtr.h>
#include <wtf/text/WTFString.h>
namespace WebKit {
@@ -44,7 +45,7 @@
class RemoteLegacyCDMFactory;
struct WebPageCreationParameters;
-class GPUProcessConnection : public RefCounted<GPUProcessConnection>, IPC::Connection::Client {
+class GPUProcessConnection : public RefCounted<GPUProcessConnection>, public CanMakeWeakPtr<GPUProcessConnection>, IPC::Connection::Client {
public:
static Ref<GPUProcessConnection> create(IPC::Connection::Identifier connectionIdentifier)
{
Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.cpp (271244 => 271245)
--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.cpp 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.cpp 2021-01-07 19:49:38 UTC (rev 271245)
@@ -44,19 +44,13 @@
Ref<RemoteAudioSourceProvider> RemoteAudioSourceProvider::create(WebCore::MediaPlayerIdentifier identifier, WTF::LoggerHelper& helper)
{
auto provider = adoptRef(*new RemoteAudioSourceProvider(identifier, helper));
-
- auto& gpuProcessConnection = WebProcess::singleton().ensureGPUProcessConnection();
- gpuProcessConnection.audioSourceProviderManager().addProvider(provider.copyRef());
-
-#if ENABLE(WEB_AUDIO)
- gpuProcessConnection.connection().send(Messages::RemoteMediaPlayerProxy::CreateAudioSourceProvider { }, provider->identifier());
-#endif
-
+ provider->m_gpuProcessConnection->audioSourceProviderManager().addProvider(provider.copyRef());
return provider;
}
RemoteAudioSourceProvider::RemoteAudioSourceProvider(MediaPlayerIdentifier identifier, WTF::LoggerHelper& helper)
: m_identifier(identifier)
+ , m_gpuProcessConnection(makeWeakPtr(WebProcess::singleton().ensureGPUProcessConnection()))
#if !RELEASE_LOG_DISABLED
, m_logger(helper.logger())
, m_logIdentifier(helper.logIdentifier())
@@ -64,6 +58,10 @@
{
ASSERT(isMainThread());
UNUSED_PARAM(helper);
+
+#if ENABLE(WEB_AUDIO)
+ m_gpuProcessConnection->connection().send(Messages::RemoteMediaPlayerProxy::CreateAudioSourceProvider { }, identifier);
+#endif
}
RemoteAudioSourceProvider::~RemoteAudioSourceProvider()
@@ -73,12 +71,14 @@
void RemoteAudioSourceProvider::close()
{
ASSERT(isMainThread());
- WebProcess::singleton().ensureGPUProcessConnection().audioSourceProviderManager().removeProvider(m_identifier);
+ if (m_gpuProcessConnection)
+ m_gpuProcessConnection->audioSourceProviderManager().removeProvider(m_identifier);
}
void RemoteAudioSourceProvider::hasNewClient(AudioSourceProviderClient* client)
{
- WebProcess::singleton().ensureGPUProcessConnection().connection().send(Messages::RemoteMediaPlayerProxy::SetShouldEnableAudioSourceProvider { !!client }, m_identifier);
+ if (m_gpuProcessConnection)
+ m_gpuProcessConnection->connection().send(Messages::RemoteMediaPlayerProxy::SetShouldEnableAudioSourceProvider { !!client }, m_identifier);
}
void RemoteAudioSourceProvider::audioSamplesAvailable(const PlatformAudioData& data, const AudioStreamDescription& description, size_t size)
Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.h (271244 => 271245)
--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.h 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteAudioSourceProvider.h 2021-01-07 19:49:38 UTC (rev 271245)
@@ -27,6 +27,7 @@
#if ENABLE(GPU_PROCESS) && ENABLE(WEB_AUDIO) && PLATFORM(COCOA)
+#include "GPUProcessConnection.h"
#include <WebCore/MediaPlayerIdentifier.h>
#include <WebCore/WebAudioSourceProviderCocoa.h>
#include <wtf/LoggerHelper.h>
@@ -65,6 +66,7 @@
#endif
WebCore::MediaPlayerIdentifier m_identifier;
+ WeakPtr<GPUProcessConnection> m_gpuProcessConnection;
#if !RELEASE_LOG_DISABLED
Ref<const Logger> m_logger;
const void* m_logIdentifier;
Modified: trunk/Tools/ChangeLog (271244 => 271245)
--- trunk/Tools/ChangeLog 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Tools/ChangeLog 2021-01-07 19:49:38 UTC (rev 271245)
@@ -1,3 +1,17 @@
+2021-01-07 Chris Dumez <[email protected]>
+
+ [GPUProcess] Implement GPUProcess crash recovery for MediaElementAudioSourceNode
+ https://bugs.webkit.org/show_bug.cgi?id=220391
+
+ Reviewed by Geoffrey Garen.
+
+ Add API test coverage.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm:
+ (TEST):
+ * TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html: Added.
+
2021-01-07 Sam Sneddon <[email protected]>
LayoutTestFinder should be in charge of finding layout tests
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (271244 => 271245)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-01-07 19:49:38 UTC (rev 271245)
@@ -259,6 +259,7 @@
468BC45522653A1000A36C96 /* open-window-then-write-to-it.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 468BC454226539C800A36C96 /* open-window-then-write-to-it.html */; };
468F2F942368DAF100F4B864 /* window-open-then-document-open.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 468F2F932368DAA700F4B864 /* window-open-then-document-open.html */; };
46918EFC2237283C00468DFE /* DeviceOrientation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46918EFB2237283500468DFE /* DeviceOrientation.mm */; };
+ 46A44A5425A7830300F61E16 /* webaudio-createMediaElementSource.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */; };
46A46A1A2575645600A1B118 /* SessionStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A46A192575645600A1B118 /* SessionStorage.mm */; };
46A911592108E6780078D40D /* CustomUserAgent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 46A911582108E66B0078D40D /* CustomUserAgent.mm */; };
46AE5A3720F9066D00E0873E /* SimpleServiceWorkerRegistrations-4.sqlite3 in Copy Resources */ = {isa = PBXBuildFile; fileRef = 4656A75720F9054F0002E21F /* SimpleServiceWorkerRegistrations-4.sqlite3 */; };
@@ -1685,6 +1686,7 @@
5703BB8D2463F88700475FB2 /* web-authentication-make-credential-la-no-attestation.html in Copy Resources */,
57EDFC5C245A1A3F00959521 /* web-authentication-make-credential-la-no-mock.html in Copy Resources */,
5742178E2400D2DF002B303D /* web-authentication-make-credential-la.html in Copy Resources */,
+ 46A44A5425A7830300F61E16 /* webaudio-createMediaElementSource.html in Copy Resources */,
1C2B81861C89259D00A5529F /* webfont.html in Copy Resources */,
31E9BDA3247F5729002E51A2 /* webgl.html in Copy Resources */,
51714EB41CF8C78C004723C4 /* WebProcessKillIDBCleanup-1.html in Copy Resources */,
@@ -1999,6 +2001,7 @@
468BC454226539C800A36C96 /* open-window-then-write-to-it.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "open-window-then-write-to-it.html"; sourceTree = "<group>"; };
468F2F932368DAA700F4B864 /* window-open-then-document-open.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "window-open-then-document-open.html"; sourceTree = "<group>"; };
46918EFB2237283500468DFE /* DeviceOrientation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DeviceOrientation.mm; sourceTree = "<group>"; };
+ 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "webaudio-createMediaElementSource.html"; sourceTree = "<group>"; };
46A46A192575645600A1B118 /* SessionStorage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SessionStorage.mm; sourceTree = "<group>"; };
46A911582108E66B0078D40D /* CustomUserAgent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CustomUserAgent.mm; sourceTree = "<group>"; };
46C1EA9725758805005E409E /* alert.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = alert.html; sourceTree = "<group>"; };
@@ -3983,6 +3986,7 @@
5703BB8C2463F87200475FB2 /* web-authentication-make-credential-la-no-attestation.html */,
57EDFC5B245A18F500959521 /* web-authentication-make-credential-la-no-mock.html */,
5742178D2400D26C002B303D /* web-authentication-make-credential-la.html */,
+ 46A44A5325A782DD00F61E16 /* webaudio-createMediaElementSource.html */,
51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */,
51714EB31CF8C761004723C4 /* WebProcessKillIDBCleanup-2.html */,
5120C83B1E674E350025B250 /* WebsiteDataStoreCustomPaths.html */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm (271244 => 271245)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm 2021-01-07 19:34:47 UTC (rev 271244)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm 2021-01-07 19:49:38 UTC (rev 271245)
@@ -291,6 +291,72 @@
EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]);
}
+TEST(GPUProcess, CrashWhilePlayingAudioViaCreateMediaElementSource)
+{
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
+ if ([feature.key isEqualToString:@"UseGPUProcessForMediaEnabled"]) {
+ [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature];
+ break;
+ }
+ }
+
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]);
+ [webView synchronouslyLoadTestPageNamed:@"webaudio-createMediaElementSource"];
+
+ __block bool done = false;
+ [webView evaluateJavaScript:@"document.getElementById('testButton').click()" completionHandler:^(id result, NSError *error) {
+ EXPECT_TRUE(!error);
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ auto webViewPID = [webView _webProcessIdentifier];
+
+ // The GPU process should get launched.
+ auto* processPool = configuration.get().processPool;
+ unsigned timeout = 0;
+ while (![processPool _gpuProcessIdentifier] && timeout++ < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+
+ EXPECT_NE([processPool _gpuProcessIdentifier], 0);
+ if (![processPool _gpuProcessIdentifier])
+ return;
+ auto gpuProcessPID = [processPool _gpuProcessIdentifier];
+
+ // Audio should be playing.
+ timeout = 0;
+ while (![webView _isPlayingAudio] && timeout++ < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+ EXPECT_TRUE([webView _isPlayingAudio]);
+
+ // Kill the GPU Process.
+ kill(gpuProcessPID, 9);
+
+ // GPU Process should get relaunched.
+ timeout = 0;
+ while ((![processPool _gpuProcessIdentifier] || [processPool _gpuProcessIdentifier] == gpuProcessPID) && timeout++ < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+ EXPECT_NE([processPool _gpuProcessIdentifier], 0);
+ EXPECT_NE([processPool _gpuProcessIdentifier], gpuProcessPID);
+ gpuProcessPID = [processPool _gpuProcessIdentifier];
+
+ // Make sure the WebProcess did not crash.
+ EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]);
+
+ // FIXME: On iOS, video resumes after the GPU process crash but audio does not.
+#if !PLATFORM(IOS)
+ // Audio should resume playing.
+ timeout = 0;
+ while (![webView _isPlayingAudio] && timeout++ < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+ EXPECT_TRUE([webView _isPlayingAudio]);
+#endif
+
+ EXPECT_EQ(gpuProcessPID, [processPool _gpuProcessIdentifier]);
+ EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]);
+}
+
static NSString *testCanvasPage = @"<body> \n"
"<canvas id='myCanvas' width='400px' height='400px'>\n"
"<script> \n"
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html (0 => 271245)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/webaudio-createMediaElementSource.html 2021-01-07 19:49:38 UTC (rev 271245)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<script>
+ function handleLoaded() {
+ context = new (window.AudioContext || window.webkitAudioContext)();
+ var myAudio = document.querySelector('audio');
+ myAudio = new Audio();
+ myAudio.src = ""
+ var source = context.createMediaElementSource(myAudio);
+ var gainNode = context.createGain();
+ source.connect(gainNode);
+ gainNode.connect(context.destination);
+
+ testButton._onclick_ = () => {
+ context.resume();
+ myAudio.play();
+ }
+ }
+</script>
+<body _onload_=handleLoaded()>
+ <input type="button" id="testButton" value="Click me"></input>
+</body>
+<html>