Diff
Modified: trunk/Source/WebCore/ChangeLog (235473 => 235474)
--- trunk/Source/WebCore/ChangeLog 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Source/WebCore/ChangeLog 2018-08-29 19:39:37 UTC (rev 235474)
@@ -1,3 +1,17 @@
+2018-08-29 Jer Noble <[email protected]>
+
+ Muted elements do not have their Now Playing status updated when unmuted.
+ https://bugs.webkit.org/show_bug.cgi?id=189069
+
+ Reviewed by Eric Carlson.
+
+ Schedule an updateNowPlayingInfo() when an element becomes unmuted.
+
+ * platform/audio/PlatformMediaSessionManager.h:
+ * platform/audio/mac/MediaSessionManagerMac.h:
+ * platform/audio/mac/MediaSessionManagerMac.mm:
+ (WebCore::MediaSessionManagerMac::sessionCanProduceAudioChanged):
+
2018-08-29 Wenson Hsieh <[email protected]>
Use the null string instead of std::nullopt for missing attachment file names and content types
Modified: trunk/Source/WebCore/PAL/ChangeLog (235473 => 235474)
--- trunk/Source/WebCore/PAL/ChangeLog 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Source/WebCore/PAL/ChangeLog 2018-08-29 19:39:37 UTC (rev 235474)
@@ -1,3 +1,12 @@
+2018-08-29 Jer Noble <[email protected]>
+
+ Muted elements do not have their Now Playing status updated when unmuted.
+ https://bugs.webkit.org/show_bug.cgi?id=189069
+
+ Reviewed by Eric Carlson.
+
+ * pal/spi/mac/MediaRemoteSPI.h:
+
2018-08-27 Keith Rollin <[email protected]>
Unreviewed build fix -- disable LTO for production builds
Modified: trunk/Source/WebCore/PAL/pal/spi/mac/MediaRemoteSPI.h (235473 => 235474)
--- trunk/Source/WebCore/PAL/pal/spi/mac/MediaRemoteSPI.h 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Source/WebCore/PAL/pal/spi/mac/MediaRemoteSPI.h 2018-08-29 19:39:37 UTC (rev 235474)
@@ -103,6 +103,7 @@
typedef uint32_t MRMediaRemoteError;
typedef struct _MROrigin *MROriginRef;
typedef struct _MRMediaRemoteCommandInfo *MRMediaRemoteCommandInfoRef;
+typedef void *MRNowPlayingClientRef;
typedef void(^MRMediaRemoteAsyncCommandHandlerBlock)(MRMediaRemoteCommand command, CFDictionaryRef options, void(^completion)(CFArrayRef));
WTF_EXTERN_C_BEGIN
Modified: trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h (235473 => 235474)
--- trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h 2018-08-29 19:39:37 UTC (rev 235474)
@@ -98,6 +98,7 @@
virtual void sessionStateChanged(PlatformMediaSession&);
virtual void sessionDidEndRemoteScrubbing(const PlatformMediaSession&) { };
virtual void clientCharacteristicsChanged(PlatformMediaSession&) { }
+ virtual void sessionCanProduceAudioChanged(PlatformMediaSession&);
#if PLATFORM(IOS)
virtual void configureWireLessTargetMonitoring() { }
@@ -110,7 +111,6 @@
Vector<PlatformMediaSession*> currentSessionsMatching(const WTF::Function<bool(const PlatformMediaSession&)>&);
void sessionIsPlayingToWirelessPlaybackTargetChanged(PlatformMediaSession&);
- void sessionCanProduceAudioChanged(PlatformMediaSession&);
protected:
friend class PlatformMediaSession;
Modified: trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.h (235473 => 235474)
--- trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.h 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.h 2018-08-29 19:39:37 UTC (rev 235474)
@@ -55,6 +55,7 @@
void sessionWillEndPlayback(PlatformMediaSession&) override;
void sessionDidEndRemoteScrubbing(const PlatformMediaSession&) override;
void clientCharacteristicsChanged(PlatformMediaSession&) override;
+ void sessionCanProduceAudioChanged(PlatformMediaSession&) override;
void updateNowPlayingInfo();
Modified: trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm (235473 => 235474)
--- trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm 2018-08-29 19:39:37 UTC (rev 235474)
@@ -104,6 +104,12 @@
LOG(Media, "MediaSessionManagerMac::clientCharacteristicsChanged");
scheduleUpdateNowPlayingInfo();
}
+
+void MediaSessionManagerMac::sessionCanProduceAudioChanged(PlatformMediaSession& session)
+{
+ PlatformMediaSessionManager::sessionCanProduceAudioChanged(session);
+ scheduleUpdateNowPlayingInfo();
+}
PlatformMediaSession* MediaSessionManagerMac::nowPlayingEligibleSession()
{
Modified: trunk/Tools/ChangeLog (235473 => 235474)
--- trunk/Tools/ChangeLog 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Tools/ChangeLog 2018-08-29 19:39:37 UTC (rev 235474)
@@ -1,3 +1,32 @@
+2018-08-29 Jer Noble <[email protected]>
+
+ Muted elements do not have their Now Playing status updated when unmuted.
+ https://bugs.webkit.org/show_bug.cgi?id=189069
+
+ Reviewed by Eric Carlson.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKitCocoa/NowPlaying.mm: Added.
+ (userInfoHasNowPlayingApplicationPID):
+ (getNowPlayingClient):
+ (getNowPlayingClientPid):
+ (NowPlayingTest::webView):
+ (NowPlayingTest::configuration):
+ (NowPlayingTest::webViewPid):
+ (NowPlayingTest::loadPage):
+ (NowPlayingTest::runScriptWithUserGesture):
+ (NowPlayingTest::runScriptWithoutUserGesture):
+ (NowPlayingTest::executeAndWaitForPlaying):
+ (NowPlayingTest::executeAndWaitForWebViewToBecomeNowPlaying):
+ (NowPlayingTest::observers):
+ (NowPlayingTest::addObserver):
+ (NowPlayingTest::removeObserver):
+ (NowPlayingTest::notificationCallback):
+ (NowPlayingTest::receivedNotification):
+ (NowPlayingTest::performAfterReceivingNotification):
+ (TEST_F):
+ * TestWebKitAPI/Tests/WebKitCocoa/now-playing.html: Added.
+
2018-08-29 Thomas Denney <[email protected]>
[WHLSL] Ensure that isLValue is copied by the rewriter
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (235473 => 235474)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2018-08-29 19:24:39 UTC (rev 235473)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2018-08-29 19:39:37 UTC (rev 235474)
@@ -718,6 +718,7 @@
CD0BD0A61F79924D001AB2CF /* ContextMenuImgWithVideo.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD0BD0A51F799220001AB2CF /* ContextMenuImgWithVideo.mm */; };
CD0BD0A81F79982D001AB2CF /* ContextMenuImgWithVideo.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CD0BD0A71F7997C2001AB2CF /* ContextMenuImgWithVideo.html */; };
CD227E44211A4D5D00D285AF /* PreferredAudioBufferSize.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD227E43211A4D5D00D285AF /* PreferredAudioBufferSize.mm */; };
+ CD2D0D1A213465560018C784 /* NowPlaying.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD2D0D19213465560018C784 /* NowPlaying.mm */; };
CD321B041E3A85FA00EB21C8 /* video-with-muted-audio-and-webaudio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CD321B031E3A84B700EB21C8 /* video-with-muted-audio-and-webaudio.html */; };
CD577799211CE0E4001B371E /* web-audio-only.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CD577798211CDE8F001B371E /* web-audio-only.html */; };
CD57779C211CE91F001B371E /* audio-with-web-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CD57779A211CE6B7001B371E /* audio-with-web-audio.html */; };
@@ -734,6 +735,7 @@
CDA3159A1ED548F1009F60D3 /* MediaPlaybackSleepAssertion.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDA315991ED540A5009F60D3 /* MediaPlaybackSleepAssertion.html */; };
CDA3159D1ED5643F009F60D3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDA3159C1ED5643F009F60D3 /* IOKit.framework */; };
CDB4115A1E0B00DB00EAD352 /* video-with-muted-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDB411591E09DA8E00EAD352 /* video-with-muted-audio.html */; };
+ CDB5DFFF213610FA00D3E189 /* now-playing.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDB5DFFE21360ED800D3E189 /* now-playing.html */; };
CDBFCC451A9FF45300A7B691 /* FullscreenZoomInitialFrame.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDBFCC431A9FF44800A7B691 /* FullscreenZoomInitialFrame.mm */; };
CDBFCC461A9FF49E00A7B691 /* FullscreenZoomInitialFrame.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDBFCC421A9FF44800A7B691 /* FullscreenZoomInitialFrame.html */; };
CDC8E48D1BC5CB4500594FEC /* AudioSessionCategoryIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDC8E4851BC5B19400594FEC /* AudioSessionCategoryIOS.mm */; };
@@ -1121,6 +1123,7 @@
5797FE331EB15AB100B2F4A0 /* navigation-client-default-crypto.html in Copy Resources */,
C99B675F1E39736F00FC6C80 /* no-autoplay-with-controls.html in Copy Resources */,
466C3843210637DE006A88DE /* notify-resourceLoadObserver.html in Copy Resources */,
+ CDB5DFFF213610FA00D3E189 /* now-playing.html in Copy Resources */,
93E2D2761ED7D53200FA76F6 /* offscreen-iframe-of-media-document.html in Copy Resources */,
CEA6CF2819CCF69D0064F5A7 /* open-and-close-window.html in Copy Resources */,
7CCB99231D3B4A46003922F6 /* open-multiple-external-url.html in Copy Resources */,
@@ -1932,6 +1935,7 @@
CD0BD0A71F7997C2001AB2CF /* ContextMenuImgWithVideo.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = ContextMenuImgWithVideo.html; sourceTree = "<group>"; };
CD225C071C45A69200140761 /* ParsedContentRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParsedContentRange.cpp; sourceTree = "<group>"; };
CD227E43211A4D5D00D285AF /* PreferredAudioBufferSize.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PreferredAudioBufferSize.mm; sourceTree = "<group>"; };
+ CD2D0D19213465560018C784 /* NowPlaying.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NowPlaying.mm; sourceTree = "<group>"; };
CD321B031E3A84B700EB21C8 /* video-with-muted-audio-and-webaudio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "video-with-muted-audio-and-webaudio.html"; sourceTree = "<group>"; };
CD5393C71757BA9700C07123 /* MD5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MD5.cpp; sourceTree = "<group>"; };
CD5393C91757BAC400C07123 /* SHA1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SHA1.cpp; sourceTree = "<group>"; };
@@ -1955,6 +1959,7 @@
CDA315991ED540A5009F60D3 /* MediaPlaybackSleepAssertion.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = MediaPlaybackSleepAssertion.html; sourceTree = "<group>"; };
CDA3159C1ED5643F009F60D3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
CDB411591E09DA8E00EAD352 /* video-with-muted-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "video-with-muted-audio.html"; sourceTree = "<group>"; };
+ CDB5DFFE21360ED800D3E189 /* now-playing.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "now-playing.html"; sourceTree = "<group>"; };
CDBFCC421A9FF44800A7B691 /* FullscreenZoomInitialFrame.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = FullscreenZoomInitialFrame.html; sourceTree = "<group>"; };
CDBFCC431A9FF44800A7B691 /* FullscreenZoomInitialFrame.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FullscreenZoomInitialFrame.mm; sourceTree = "<group>"; };
CDC2C7141797089D00E627FB /* TimeRanges.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TimeRanges.cpp; sourceTree = "<group>"; };
@@ -2350,6 +2355,7 @@
51CD1C6A1B38CE3600142CA5 /* ModalAlerts.mm */,
1ABC3DED1899BE6D004F0626 /* Navigation.mm */,
5CAE4637201937CD0051610F /* NetworkProcessCrashNonPersistentDataStore.mm */,
+ CD2D0D19213465560018C784 /* NowPlaying.mm */,
2ECFF5541D9B12F800B55394 /* NowPlayingControlsTests.mm */,
A10F047C1E3AD29C00C95E19 /* NSFileManagerExtras.mm */,
37A22AA51DCAA27200AFBFC4 /* ObservedRenderingProgressEventsAfterCrash.mm */,
@@ -2720,6 +2726,7 @@
9BCD4119206D5ED7001D71BE /* mso-list-on-h4.html */,
9BF356CC202D44F200F71160 /* mso-list.html */,
466C3842210637CE006A88DE /* notify-resourceLoadObserver.html */,
+ CDB5DFFE21360ED800D3E189 /* now-playing.html */,
93E2D2751ED7D51700FA76F6 /* offscreen-iframe-of-media-document.html */,
7CCB99221D3B44E7003922F6 /* open-multiple-external-url.html */,
CEBCA1341E3A803400C73293 /* page-with-csp-iframe.html */,
@@ -3867,6 +3874,7 @@
7CCE7F051A411AE600447C4C /* NewFirstVisuallyNonEmptyLayoutFrames.cpp in Sources */,
0F5651F71FCE4DDC00310FBC /* NoHistoryItemScrollToFragment.mm in Sources */,
83F22C6420B355F80034277E /* NoPolicyDelegateResponse.mm in Sources */,
+ CD2D0D1A213465560018C784 /* NowPlaying.mm in Sources */,
2ECFF5551D9B12F800B55394 /* NowPlayingControlsTests.mm in Sources */,
A10F047E1E3AD29C00C95E19 /* NSFileManagerExtras.mm in Sources */,
37A22AA71DCAA27200AFBFC4 /* ObservedRenderingProgressEventsAfterCrash.mm in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/NowPlaying.mm (0 => 235474)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/NowPlaying.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/NowPlaying.mm 2018-08-29 19:39:37 UTC (rev 235474)
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if WK_API_ENABLED && PLATFORM(COCOA) && USE(MEDIAREMOTE)
+
+#import "PlatformUtilities.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKWebViewPrivate.h>
+#import <pal/spi/mac/MediaRemoteSPI.h>
+#import <wtf/Function.h>
+#import <wtf/HashMap.h>
+#import <wtf/HashSet.h>
+#import <wtf/NeverDestroyed.h>
+#import <wtf/SoftLinking.h>
+#import <wtf/text/WTFString.h>
+
+SOFT_LINK_PRIVATE_FRAMEWORK(MediaRemote)
+SOFT_LINK(MediaRemote, MRMediaRemoteSetWantsNowPlayingNotifications, void, (bool wantsNotifications), (wantsNotifications))
+SOFT_LINK(MediaRemote, MRMediaRemoteGetNowPlayingClient, void, (dispatch_queue_t queue, void(^completion)(MRNowPlayingClientRef, CFErrorRef)), (queue, completion))
+SOFT_LINK(MediaRemote, MRNowPlayingClientGetProcessIdentifier, pid_t, (MRNowPlayingClientRef client), (client))
+SOFT_LINK_CONSTANT(MediaRemote, kMRMediaRemoteNowPlayingApplicationDidChangeNotification, CFStringRef)
+SOFT_LINK_CONSTANT(MediaRemote, kMRMediaRemoteNowPlayingApplicationPIDUserInfoKey, CFStringRef)
+#define MRMediaRemoteSetWantsNowPlayingNotifications softLinkMRMediaRemoteSetWantsNowPlayingNotifications
+#define MRMediaRemoteGetNowPlayingClient softLinkMRMediaRemoteGetNowPlayingClient
+#define MRNowPlayingClientGetProcessIdentifier softLinkMRNowPlayingClientGetProcessIdentifier
+#define kMRMediaRemoteNowPlayingApplicationDidChangeNotification getkMRMediaRemoteNowPlayingApplicationDidChangeNotification()
+#define kMRMediaRemoteNowPlayingApplicationPIDUserInfoKey getkMRMediaRemoteNowPlayingApplicationPIDUserInfoKey()
+
+static bool userInfoHasNowPlayingApplicationPID(CFDictionaryRef userInfo, int32_t pid)
+{
+ CFNumberRef nowPlayingPidCF = (CFNumberRef)CFDictionaryGetValue(userInfo, kMRMediaRemoteNowPlayingApplicationPIDUserInfoKey);
+ if (!nowPlayingPidCF)
+ return false;
+
+ int32_t nowPlayingPid = 0;
+ if (!CFNumberGetValue(nowPlayingPidCF, kCFNumberSInt32Type, &nowPlayingPid))
+ return false;
+
+ return pid == nowPlayingPid;
+}
+
+static RetainPtr<MRNowPlayingClientRef> getNowPlayingClient()
+{
+ bool gotNowPlaying = false;
+ RetainPtr<MRNowPlayingClientRef> nowPlayingClient;
+ MRMediaRemoteGetNowPlayingClient(dispatch_get_main_queue(), [&] (MRNowPlayingClientRef player, CFErrorRef error) {
+ if (!error && player)
+ nowPlayingClient = player;
+ gotNowPlaying = true;
+ });
+ TestWebKitAPI::Util::run(&gotNowPlaying);
+ return nowPlayingClient;
+}
+
+static pid_t getNowPlayingClientPid()
+{
+ return MRNowPlayingClientGetProcessIdentifier(getNowPlayingClient().get());
+}
+
+class NowPlayingTest : public testing::Test {
+public:
+ void SetUp() override
+ {
+ addObserver(*this);
+
+ _configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ [_configuration setMediaTypesRequiringUserActionForPlayback:WKAudiovisualMediaTypeAudio];
+
+ _webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:_configuration.get() addToWindow:YES]);
+ }
+
+ void TearDown() override
+ {
+ removeObserver(*this);
+ }
+
+ TestWKWebView* webView() { return _webView.get(); }
+ WKWebViewConfiguration* configuration() { return _configuration.get(); }
+
+ pid_t webViewPid() { return [_webView _webProcessIdentifier]; }
+
+ void loadPage(const String& name)
+ {
+ [_webView synchronouslyLoadTestPageNamed:name];
+ }
+
+ void runScriptWithUserGesture(const String& script)
+ {
+ bool complete = false;
+ [_webView evaluateJavaScript:script completionHandler:[&] (id, NSError *) { complete = true; }];
+ TestWebKitAPI::Util::run(&complete);
+ }
+
+ void runScriptWithoutUserGesture(const String& script)
+ {
+ bool complete = false;
+ [_webView _evaluateJavaScriptWithoutUserGesture:script completionHandler:[&] (id, NSError *) { complete = true; }];
+ TestWebKitAPI::Util::run(&complete);
+ }
+
+ void executeAndWaitForPlaying(Function<void()>&& callback)
+ {
+ bool isPlaying = false;
+ [_webView performAfterReceivingMessage:@"playing" action:[&] { isPlaying = true; }];
+ callback();
+ TestWebKitAPI::Util::run(&isPlaying);
+ }
+
+ void executeAndWaitForWebViewToBecomeNowPlaying(Function<void()>&& callback)
+ {
+ bool becameNowPlaying = false;
+ performAfterReceivingNotification(kMRMediaRemoteNowPlayingApplicationDidChangeNotification, [&] (CFDictionaryRef userInfo) -> bool {
+ if (!userInfoHasNowPlayingApplicationPID(userInfo, webViewPid()))
+ return false;
+
+ becameNowPlaying = true;
+ return true;
+ });
+ callback();
+ TestWebKitAPI::Util::run(&becameNowPlaying);
+ }
+
+private:
+ using ObserverSet = HashSet<NowPlayingTest*>;
+ static ObserverSet& observers()
+ {
+ static NeverDestroyed<ObserverSet> observers { };
+ return observers.get();
+ }
+
+ static void addObserver(NowPlayingTest& test)
+ {
+ observers().add(&test);
+ if (observers().size() == 1) {
+ CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), nullptr, ¬ificationCallback, kMRMediaRemoteNowPlayingApplicationDidChangeNotification, nullptr, CFNotificationSuspensionBehaviorDeliverImmediately);
+ MRMediaRemoteSetWantsNowPlayingNotifications(true);
+ }
+ }
+
+ static void removeObserver(NowPlayingTest& test)
+ {
+ observers().remove(&test);
+ if (!observers().size()) {
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), nullptr, kMRMediaRemoteNowPlayingApplicationDidChangeNotification, nullptr);
+ MRMediaRemoteSetWantsNowPlayingNotifications(false);
+ }
+ }
+
+ static void notificationCallback(CFNotificationCenterRef center, void *observer, CFNotificationName name, const void *object, CFDictionaryRef userInfo)
+ {
+ ObserverSet observersCopy = observers();
+ for (auto* observer : observersCopy)
+ observer->receivedNotification(name, userInfo);
+ }
+
+ void receivedNotification(CFNotificationName name, CFDictionaryRef userInfo)
+ {
+ auto callbackIter = _callbacks.find(name);
+ if (callbackIter == _callbacks.end())
+ return;
+ auto& callback = callbackIter->value;
+ if (callback(userInfo))
+ _callbacks.remove(callbackIter);
+ }
+
+ using NotificationCallback = Function<bool(CFDictionaryRef)>;
+ void performAfterReceivingNotification(CFNotificationName name, NotificationCallback&& callback)
+ {
+ _callbacks.add(name, WTFMove(callback));
+ }
+
+ RetainPtr<WKWebViewConfiguration> _configuration;
+ RetainPtr<TestWKWebView> _webView;
+ HashMap<CFNotificationName, NotificationCallback> _callbacks;
+};
+
+TEST_F(NowPlayingTest, AudioElement)
+{
+ executeAndWaitForWebViewToBecomeNowPlaying([&] {
+ executeAndWaitForPlaying([&] {
+ loadPage("now-playing");
+ runScriptWithoutUserGesture("createMediaElement({type:'audio', hasAudio:true})");
+ runScriptWithUserGesture("play()");
+ });
+ });
+}
+
+TEST_F(NowPlayingTest, VideoElementWithAudio)
+{
+ executeAndWaitForWebViewToBecomeNowPlaying([&] {
+ executeAndWaitForPlaying([&] {
+ loadPage("now-playing");
+ runScriptWithoutUserGesture("createMediaElement({type:'video', hasAudio:true})");
+ runScriptWithUserGesture("play()");
+ });
+ });
+}
+
+TEST_F(NowPlayingTest, VideoElementWithoutAudio)
+{
+ executeAndWaitForPlaying([&] {
+ loadPage("now-playing");
+ runScriptWithoutUserGesture("createMediaElement({type:'video', hasAudio:false})");
+ runScriptWithoutUserGesture("play()");
+ });
+
+ ASSERT_NE(webViewPid(), getNowPlayingClientPid());
+}
+
+TEST_F(NowPlayingTest, VideoElementWithMutedAudio)
+{
+ executeAndWaitForPlaying([&] {
+ loadPage("now-playing");
+ runScriptWithoutUserGesture("createMediaElement({type:'video', hasAudio:true, muted:true})");
+ runScriptWithoutUserGesture("play()");
+ });
+ ASSERT_NE(webViewPid(), getNowPlayingClientPid());
+}
+
+TEST_F(NowPlayingTest, VideoElementWithMutedAudioUnmutedWithUserGesture)
+{
+ executeAndWaitForPlaying([&] {
+ loadPage("now-playing");
+ runScriptWithoutUserGesture("createMediaElement({type:'video', hasAudio:true, muted:true})");
+ runScriptWithoutUserGesture("play()");
+ });
+ ASSERT_NE(webViewPid(), getNowPlayingClientPid());
+
+ executeAndWaitForWebViewToBecomeNowPlaying([&] {
+ runScriptWithUserGesture("unmute()");
+ });
+}
+
+TEST_F(NowPlayingTest, VideoElementWithoutAudioPlayWithUserGesture)
+{
+ executeAndWaitForPlaying([&] {
+ loadPage("now-playing");
+ runScriptWithoutUserGesture("createMediaElement({type:'video', hasAudio:true, muted:true})");
+ runScriptWithoutUserGesture("play()");
+ });
+ ASSERT_NE(webViewPid(), getNowPlayingClientPid());
+
+ executeAndWaitForPlaying([&] {
+ runScriptWithUserGesture("play()");
+ });
+
+ ASSERT_NE(webViewPid(), getNowPlayingClientPid());
+}
+
+#endif // WK_API_ENABLED && PLATFORM(COCOA) && USE(MEDIAREMOTE)
Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/now-playing.html (0 => 235474)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/now-playing.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/now-playing.html 2018-08-29 19:39:37 UTC (rev 235474)
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+ var mediaElement;
+ function createMediaElement(parameters) {
+ if (parameters.type === 'video')
+ mediaElement = document.createElement('video');
+ else if (parameters.type === 'audio')
+ mediaElement = document.createElement('audio');
+ else
+ throw 'Necessary parameter not provided';
+
+ if (parameters.autoplay)
+ mediaElement.autoplay = true;
+
+ if (parameters.muted)
+ mediaElement.muted = true;
+
+ if (parameters.controls)
+ mediaElement.controls = true;
+
+ if (parameters.hasAudio)
+ mediaElement.src = '';
+ else
+ mediaElement.src = '';
+
+ document.body.appendChild(mediaElement);
+ }
+
+ function playing() {
+ window.webkit.messageHandlers.testHandler.postMessage('playing');
+ }
+
+ function notPlaying() {
+ window.webkit.messageHandlers.testHandler.postMessage('not playing');
+ }
+
+ function play() {
+ mediaElement.play().then(playing, notPlaying);
+ }
+
+ function unmute() {
+ mediaElement.muted = false;
+ }
+ </script>
+</head>
+<body>
+</body>
+</html>