Title: [278336] trunk
Revision
278336
Author
[email protected]
Date
2021-06-01 18:20:38 -0700 (Tue, 01 Jun 2021)

Log Message

LayoutTests/imported/w3c:
MediaSession.coordinator should not be optional, relying on coordinator state change instead
https://bugs.webkit.org/show_bug.cgi?id=226328
rdar://77461335

Reviewed by Eric Carlson.

* web-platform-tests/mediasession/idlharness.window-expected.txt:

Source/WebCore:
MediaSession.coordinator should not be optional, relying on coordinator state change instead
https://bugs.webkit.org/show_bug.cgi?id=226328
rdar://77461335

Reviewed by Eric Carlson.

The coordinator was a read-only optional attribute of the MediaSession element.
Testing if the attribute was to be used to determine if a MediaSessionCoordinator
was now available and for the MediaSession to join it. This made the use of an external
polyfill difficult and enforcing the validity of an user created custom
MediaSessionCoordinator due to IDL semantics limitations hard.
We instead always create a MediaSessionCoordinator which in its default state is Closed.
Once this state is changed to Waiting and an event is fire the MediaSession can now
join it.

* Modules/mediasession/MediaSession.cpp:
(WebCore::MediaSession::MediaSession): MediaSession no longer needs to fire event.
Remove no longer necessary inheritance and async event queue.
(WebCore::MediaSession::create): Drive-by fix, don't call suspendIfNeeded() in the constructor.
(WebCore::MediaSession::createCoordinator): Make method private.
* Modules/mediasession/MediaSession.h:
(WebCore::MediaSession::coordinator const): MediaSessionCoordinator always exists. Return reference instead.
* Modules/mediasession/MediaSession.idl: Amend definition, remove EventHandler
* Modules/mediasession/MediaSessionCoordinator.cpp:
(WebCore::MediaSessionCoordinator::create):
(WebCore::MediaSessionCoordinator::MediaSessionCoordinator):
(WebCore::MediaSessionCoordinator::setMediaSessionCoordinatorPrivate):
(WebCore::MediaSessionCoordinator::virtualHasPendingActivity const):
(WebCore::MediaSessionCoordinator::join):
(WebCore::MediaSessionCoordinator::close):
(WebCore::MediaSessionCoordinator::coordinatorStateChanged):
* Modules/mediasession/MediaSessionCoordinator.h:
* Modules/mediasession/MediaSessionCoordinator.idl: Added new EventHandler attribute.
* Modules/mediasession/MediaSessionCoordinatorMixin.idl: Update for new API definition.
* dom/EventNames.h:
* dom/EventTargetFactory.in:
* page/Page.cpp:
(WebCore::Page::setMediaSessionCoordinator):
(WebCore::Page::invalidateMediaSessionCoordinator):
* testing/Internals.cpp:
(WebCore::Internals::registerMockMediaSessionCoordinator):

Tools:
MediaSession.coordinator should not be optional, relying on coordinator readyState change instead
https://bugs.webkit.org/show_bug.cgi?id=226328
rdar://77461335

Reviewed by Eric Carlson.

* TestWebKitAPI/Tests/WebKit/MediaSessionCoordinatorTest.mm:
(TestWebKitAPI::MediaSessionCoordinatorTest::createCoordinator): Change test to match new API,
using coordinatorstatechange event instead.
* TestWebKitAPI/Tests/WebKitCocoa/media-remote.html:

LayoutTests:
MediaSession.coordinator should not be optional, relying on coordinator readyState change instead
https://bugs.webkit.org/show_bug.cgi?id=226328
rdar://77461335

Reviewed by Eric Carlson.

* media/media-session/mock-coordinator-expected.txt:
* media/media-session/mock-coordinator.html: Change test to match new API.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (278335 => 278336)


--- trunk/LayoutTests/ChangeLog	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/LayoutTests/ChangeLog	2021-06-02 01:20:38 UTC (rev 278336)
@@ -1,3 +1,14 @@
+2021-06-01  Jean-Yves Avenard  <[email protected]>
+
+        MediaSession.coordinator should not be optional, relying on coordinator readyState change instead
+        https://bugs.webkit.org/show_bug.cgi?id=226328
+        rdar://77461335
+
+        Reviewed by Eric Carlson.
+
+        * media/media-session/mock-coordinator-expected.txt:
+        * media/media-session/mock-coordinator.html: Change test to match new API.
+
 2021-06-01  Chris Dumez  <[email protected]>
 
         Fix unsafe access to m_upload in XMLHttpRequest::virtualHasPendingActivity()

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (278335 => 278336)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-06-02 01:20:38 UTC (rev 278336)
@@ -1,3 +1,13 @@
+2021-06-01  Jean-Yves Avenard  <[email protected]>
+
+        MediaSession.coordinator should not be optional, relying on coordinator state change instead
+        https://bugs.webkit.org/show_bug.cgi?id=226328
+        rdar://77461335
+
+        Reviewed by Eric Carlson.
+
+        * web-platform-tests/mediasession/idlharness.window-expected.txt:
+
 2021-06-01  Cathie Chen  <[email protected]>
 
         Update tests of mapping width and height attributes to aspect-ratio from WPT

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/mediasession/idlharness.window-expected.txt (278335 => 278336)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/mediasession/idlharness.window-expected.txt	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/mediasession/idlharness.window-expected.txt	2021-06-02 01:20:38 UTC (rev 278336)
@@ -12,14 +12,10 @@
 PASS Navigator includes NavigatorCookies: member names are unique
 PASS Navigator includes NavigatorPlugins: member names are unique
 PASS Navigator includes NavigatorConcurrentHardware: member names are unique
-FAIL MediaSession interface: existence and properties of interface object assert_equals: prototype of self's property "MediaSession" is not Function.prototype expected function "function () {
-    [native code]
-}" but got function "function EventTarget() {
-    [native code]
-}"
+PASS MediaSession interface: existence and properties of interface object
 PASS MediaSession interface object length
 PASS MediaSession interface object name
-FAIL MediaSession interface: existence and properties of interface prototype object assert_equals: prototype of MediaSession.prototype is not Object.prototype expected object "[object Object]" but got object "[object EventTarget]"
+PASS MediaSession interface: existence and properties of interface prototype object
 PASS MediaSession interface: existence and properties of interface prototype object's "constructor" property
 PASS MediaSession interface: existence and properties of interface prototype object's @@unscopables property
 PASS MediaSession interface: attribute metadata

Modified: trunk/LayoutTests/media/media-session/mock-coordinator-expected.txt (278335 => 278336)


--- trunk/LayoutTests/media/media-session/mock-coordinator-expected.txt	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/LayoutTests/media/media-session/mock-coordinator-expected.txt	2021-06-02 01:20:38 UTC (rev 278336)
@@ -1,13 +1,12 @@
 
-** There should be no mediaSession.coordinator initially.
-EXPECTED (navigator.mediaSession.coordinator == 'undefined') OK
+** There mediaSession.coordinator.state should be closed initially.
+EXPECTED (navigator.mediaSession.coordinator.state == 'closed') OK
 
-** Test that mediaSession.coordinatorchange event is fired when it changes.
+** Test that mediaSession.coordinator.coordinatorstatechange event is fired when it changes.
 RUN(internals.registerMockMediaSessionCoordinator(changeHandler))
-EVENT(coordinatorchange)
-EXPECTED (navigator.mediaSession.coordinator != 'undefined') OK
+EVENT(coordinatorstatechange STATE(waiting)
 
-** navigator.mediaSession.coordinator.state should be "waiting" intitially
+** navigator.mediaSession.coordinator.state should be "waiting" initially
 EXPECTED (navigator.mediaSession.coordinator.state == 'waiting') OK
 
 ** Test that when coordinator methods fail and promises reject before mediaSession.join() is called.
@@ -78,9 +77,9 @@
 
 RUN(internals.setMockMediaSessionCoordinatorCommandsShouldFail(false))
 RUN(promise = navigator.mediaSession.coordinator.join())
+EVENT(coordinatorstatechange STATE(joined)
 Promise resolved OK
 EXPECTED (navigator.mediaSession.coordinator.state == 'joined') OK
-EXPECTED (latestChange == 'coordinatorStateChanged') OK
 
 ** Test that when coordinator methods succeed, promises resolve and mediaSession action handlers are called.
 RUN(promise = navigator.mediaSession.coordinator.play())
@@ -149,8 +148,11 @@
 
 ** Leave the session
 RUN(navigator.mediaSession.coordinator.leave())
+EXPECTED (latestChange == 'playbackStateChanged') OK
+EXPECTED (latestChange == 'playbackStateChanged') OK
+EXPECTED (latestChange == 'playbackStateChanged') OK
+EVENT(coordinatorstatechange STATE(closed)
 EXPECTED (navigator.mediaSession.coordinator.state == 'closed') OK
-EXPECTED (latestChange == 'coordinatorStateChanged') OK
 
 ** Test that when coordinator methods fail and promises reject after mediaSession.leave() has been called.
 RUN(promise = navigator.mediaSession.coordinator.play())

Modified: trunk/LayoutTests/media/media-session/mock-coordinator.html (278335 => 278336)


--- trunk/LayoutTests/media/media-session/mock-coordinator.html	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/LayoutTests/media/media-session/mock-coordinator.html	2021-06-02 01:20:38 UTC (rev 278336)
@@ -33,10 +33,10 @@
 
         let changePromise = () => {
             return new Promise(resolve => {
-                navigator.mediaSession.addEventListener('coordinatorchange', (event) => {
-                    consoleWrite(`EVENT(${event.type})`);
+                navigator.mediaSession.coordinator.addEventListener('coordinatorstatechange', (event) => {
+                    consoleWrite(`EVENT(${event.type} STATE(${navigator.mediaSession.coordinator.state})`);
                     resolve();
-                });
+                }, { once: true });
             });
         }
 
@@ -43,18 +43,16 @@
         await waitForDebugger();
 
         consoleWrite('');
-        consoleWrite('** There should be no mediaSession.coordinator initially.')
+        consoleWrite('** There mediaSession.coordinator.state should be closed initially.');
 
-        testExpected('navigator.mediaSession.coordinator', undefined);
+        testExpected('navigator.mediaSession.coordinator.state', "closed");
 
         consoleWrite('');
-        consoleWrite('** Test that mediaSession.coordinatorchange event is fired when it changes.')
+        consoleWrite('** Test that mediaSession.coordinator.coordinatorstatechange event is fired when it changes.');
 
         run('internals.registerMockMediaSessionCoordinator(changeHandler)');
 
         await changePromise();
-        
-        testExpected('navigator.mediaSession.coordinator', undefined, '!=');
 
         ['play', 'pause', 'seekto'].forEach(action ="" {
             navigator.mediaSession.setActionHandler(action, actionDetails => {
@@ -120,7 +118,7 @@
 
         // Before joining
         consoleWrite('');
-        consoleWrite('** navigator.mediaSession.coordinator.state should be "waiting" intitially')
+        consoleWrite('** navigator.mediaSession.coordinator.state should be "waiting" initially')
         testExpected('navigator.mediaSession.coordinator.state', 'waiting');
 
         consoleWrite('');
@@ -159,9 +157,9 @@
         consoleWrite('');
         run('internals.setMockMediaSessionCoordinatorCommandsShouldFail(false)');
         run('promise = navigator.mediaSession.coordinator.join()');
+        await changePromise();
         await shouldResolve(promise).then(() => { }).catch(() => { });
         testExpected('navigator.mediaSession.coordinator.state', 'joined');
-        testExpected('latestChange', 'coordinatorStateChanged');
 
         consoleWrite('');
         consoleWrite('** Test that when coordinator methods succeed, promises resolve and mediaSession action handlers are called.')
@@ -189,8 +187,9 @@
         consoleWrite('<br>');
         consoleWrite('** Leave the session')
         run('navigator.mediaSession.coordinator.leave()');
+        await changePromise();
         testExpected('navigator.mediaSession.coordinator.state', 'closed');
-        await testExpectedEventually('latestChange', 'coordinatorStateChanged', '==', 100);
+
         latestChange = '';
 
         consoleWrite('');

Modified: trunk/Source/WebCore/ChangeLog (278335 => 278336)


--- trunk/Source/WebCore/ChangeLog	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/ChangeLog	2021-06-02 01:20:38 UTC (rev 278336)
@@ -1,3 +1,47 @@
+2021-06-01  Jean-Yves Avenard  <[email protected]>
+
+        MediaSession.coordinator should not be optional, relying on coordinator state change instead
+        https://bugs.webkit.org/show_bug.cgi?id=226328
+        rdar://77461335
+
+        Reviewed by Eric Carlson.
+
+        The coordinator was a read-only optional attribute of the MediaSession element.
+        Testing if the attribute was to be used to determine if a MediaSessionCoordinator
+        was now available and for the MediaSession to join it. This made the use of an external
+        polyfill difficult and enforcing the validity of an user created custom
+        MediaSessionCoordinator due to IDL semantics limitations hard.
+        We instead always create a MediaSessionCoordinator which in its default state is Closed.
+        Once this state is changed to Waiting and an event is fire the MediaSession can now
+        join it.
+
+        * Modules/mediasession/MediaSession.cpp:
+        (WebCore::MediaSession::MediaSession): MediaSession no longer needs to fire event.
+        Remove no longer necessary inheritance and async event queue.
+        (WebCore::MediaSession::create): Drive-by fix, don't call suspendIfNeeded() in the constructor.
+        (WebCore::MediaSession::createCoordinator): Make method private.
+        * Modules/mediasession/MediaSession.h:
+        (WebCore::MediaSession::coordinator const): MediaSessionCoordinator always exists. Return reference instead.
+        * Modules/mediasession/MediaSession.idl: Amend definition, remove EventHandler
+        * Modules/mediasession/MediaSessionCoordinator.cpp:
+        (WebCore::MediaSessionCoordinator::create):
+        (WebCore::MediaSessionCoordinator::MediaSessionCoordinator):
+        (WebCore::MediaSessionCoordinator::setMediaSessionCoordinatorPrivate):
+        (WebCore::MediaSessionCoordinator::virtualHasPendingActivity const):
+        (WebCore::MediaSessionCoordinator::join):
+        (WebCore::MediaSessionCoordinator::close):
+        (WebCore::MediaSessionCoordinator::coordinatorStateChanged):
+        * Modules/mediasession/MediaSessionCoordinator.h:
+        * Modules/mediasession/MediaSessionCoordinator.idl: Added new EventHandler attribute.
+        * Modules/mediasession/MediaSessionCoordinatorMixin.idl: Update for new API definition.
+        * dom/EventNames.h:
+        * dom/EventTargetFactory.in:
+        * page/Page.cpp:
+        (WebCore::Page::setMediaSessionCoordinator):
+        (WebCore::Page::invalidateMediaSessionCoordinator):
+        * testing/Internals.cpp:
+        (WebCore::Internals::registerMockMediaSessionCoordinator):
+
 2021-06-01  Chris Dumez  <[email protected]>
 
         Drop unused AudioChannel::resizeSmaller()

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSession.cpp (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSession.cpp	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSession.cpp	2021-06-02 01:20:38 UTC (rev 278336)
@@ -128,13 +128,14 @@
 
 Ref<MediaSession> MediaSession::create(Navigator& navigator)
 {
-    return adoptRef(*new MediaSession(navigator));
+    auto session = adoptRef(*new MediaSession(navigator));
+    session->suspendIfNeeded();
+    return session;
 }
 
 MediaSession::MediaSession(Navigator& navigator)
     : ActiveDOMObject(navigator.scriptExecutionContext())
     , m_navigator(makeWeakPtr(navigator))
-    , m_asyncEventQueue(MainThreadGenericEventQueue::create(*this))
 {
     m_logger = makeRefPtr(Document::sharedLogger());
     m_logIdentifier = nextLogIdentifier();
@@ -141,24 +142,15 @@
 
 #if ENABLE(MEDIA_SESSION_COORDINATOR)
     auto* frame = navigator.frame();
-    if (auto* page = frame ? frame->page() : nullptr) {
-        if (auto coordinatorPrivate = page->mediaSessionCoordinator())
-            createCoordinator(*coordinatorPrivate);
-    }
+    if (auto* page = frame ? frame->page() : nullptr)
+        createCoordinator(page->mediaSessionCoordinator());
 #endif
 
-    suspendIfNeeded();
-
     ALWAYS_LOG(LOGIDENTIFIER);
 }
 
 MediaSession::~MediaSession() = default;
 
-bool MediaSession::virtualHasPendingActivity() const
-{
-    return m_asyncEventQueue->hasPendingActivity();
-}
-
 void MediaSession::suspend(ReasonForSuspension reason)
 {
 #if ENABLE(MEDIA_SESSION_COORDINATOR)
@@ -200,7 +192,7 @@
     notifyReadyStateObservers();
 }
 
-void MediaSession::createCoordinator(Ref<MediaSessionCoordinatorPrivate>&& coordinatorPrivate)
+void MediaSession::createCoordinator(MediaSessionCoordinatorPrivate* coordinatorPrivate)
 {
     ALWAYS_LOG(LOGIDENTIFIER);
 
@@ -207,12 +199,8 @@
     if (m_coordinator)
         m_coordinator->setMediaSession(nullptr);
 
-    m_coordinator = MediaSessionCoordinator::create(WTFMove(coordinatorPrivate));
-
-    if (m_coordinator)
-        m_coordinator->setMediaSession(this);
-
-    m_asyncEventQueue->enqueueEvent(Event::create(eventNames().coordinatorchangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
+    m_coordinator = MediaSessionCoordinator::create(scriptExecutionContext(), coordinatorPrivate);
+    m_coordinator->setMediaSession(this);
 }
 #endif
 

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSession.h (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSession.h	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSession.h	2021-06-02 01:20:38 UTC (rev 278336)
@@ -28,8 +28,7 @@
 #if ENABLE(MEDIA_SESSION)
 
 #include "ActiveDOMObject.h"
-#include "EventTarget.h"
-#include "GenericEventQueue.h"
+#include "ExceptionOr.h"
 #include "MediaPositionState.h"
 #include "MediaSessionAction.h"
 #include "MediaSessionActionHandler.h"
@@ -52,7 +51,7 @@
 class Navigator;
 template<typename> class DOMPromiseDeferred;
 
-class MediaSession : public RefCounted<MediaSession>, public ActiveDOMObject, public EventTargetWithInlineData {
+class MediaSession : public RefCounted<MediaSession>, public ActiveDOMObject, public CanMakeWeakPtr<MediaSession> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     static Ref<MediaSession> create(Navigator&);
@@ -80,8 +79,7 @@
     MediaSessionReadyState readyState() const { return m_readyState; };
     void setReadyState(MediaSessionReadyState);
 
-    MediaSessionCoordinator* coordinator() const { return m_coordinator.get(); }
-    WEBCORE_EXPORT void createCoordinator(Ref<MediaSessionCoordinatorPrivate>&&);
+    MediaSessionCoordinator& coordinator() const { return *m_coordinator; }
 #endif
 
 #if ENABLE(MEDIA_SESSION_PLAYLIST)
@@ -98,10 +96,6 @@
 
     const Logger& logger() const { return *m_logger.get(); }
 
-    // EventTarget
-    using RefCounted::ref;
-    using RefCounted::deref;
-
     class Observer : public CanMakeWeakPtr<Observer> {
     public:
         virtual ~Observer() = default;
@@ -130,15 +124,10 @@
     void notifyActionHandlerObservers();
     void notifyReadyStateObservers();
 
-    // EventTarget
-    void refEventTarget() final { ref(); }
-    void derefEventTarget() final { deref(); }
-    EventTargetInterface eventTargetInterface() const final { return MediaSessionEventTargetInterfaceType; }
-    ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
+    void createCoordinator(MediaSessionCoordinatorPrivate*);
 
     // ActiveDOMObject
     const char* activeDOMObjectName() const final { return "MediaSession"; }
-    bool virtualHasPendingActivity() const final;
     void suspend(ReasonForSuspension) final;
     void stop() final;
 
@@ -155,7 +144,6 @@
     const void* m_logIdentifier;
 
     WeakHashSet<Observer> m_observers;
-    UniqueRef<MainThreadGenericEventQueue> m_asyncEventQueue;
 
 #if ENABLE(MEDIA_SESSION_COORDINATOR)
     MediaSessionReadyState m_readyState { MediaSessionReadyState::Havenothing };

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSession.idl (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSession.idl	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSession.idl	2021-06-02 01:20:38 UTC (rev 278336)
@@ -28,8 +28,7 @@
     Conditional=MEDIA_SESSION,
     Exposed=Window,
     ExportMacro=WEBCORE_EXPORT,
-    JSGenerateToJSObject,
-] interface MediaSession : EventTarget
+] interface MediaSession
 {
     attribute MediaMetadata? metadata;
 

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.cpp (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.cpp	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.cpp	2021-06-02 01:20:38 UTC (rev 278336)
@@ -28,6 +28,7 @@
 
 #if ENABLE(MEDIA_SESSION_COORDINATOR)
 
+#include "EventNames.h"
 #include "JSDOMException.h"
 #include "JSDOMPromiseDeferred.h"
 #include "JSMediaSessionCoordinatorState.h"
@@ -47,24 +48,49 @@
     return reinterpret_cast<const void*>(++logIdentifier);
 }
 
-Ref<MediaSessionCoordinator> MediaSessionCoordinator::create(Ref<MediaSessionCoordinatorPrivate>&& privateCoordinator)
+Ref<MediaSessionCoordinator> MediaSessionCoordinator::create(ScriptExecutionContext* context, RefPtr<MediaSessionCoordinatorPrivate>&& privateCoordinator)
 {
-    return adoptRef(*new MediaSessionCoordinator(WTFMove(privateCoordinator)));
+    auto coordinator = adoptRef(*new MediaSessionCoordinator(context, WTFMove(privateCoordinator)));
+    coordinator->suspendIfNeeded();
+    return coordinator;
 }
 
-MediaSessionCoordinator::MediaSessionCoordinator(Ref<MediaSessionCoordinatorPrivate>&& privateCoordinator)
-    : m_privateCoordinator(WTFMove(privateCoordinator))
+MediaSessionCoordinator::MediaSessionCoordinator(ScriptExecutionContext* context, RefPtr<MediaSessionCoordinatorPrivate>&& privateCoordinator)
+    : ActiveDOMObject(context)
     , m_logger(makeRef(Document::sharedLogger()))
     , m_logIdentifier(nextCoordinatorLogIdentifier())
+    , m_asyncEventQueue(MainThreadGenericEventQueue::create(*this))
 {
     ALWAYS_LOG(LOGIDENTIFIER);
 
+    if (privateCoordinator)
+        setMediaSessionCoordinatorPrivate(*privateCoordinator);
+}
+
+void MediaSessionCoordinator::setMediaSessionCoordinatorPrivate(Ref<MediaSessionCoordinatorPrivate>&& privateCoordinator)
+{
+    ALWAYS_LOG(LOGIDENTIFIER);
+    if (m_privateCoordinator)
+        m_privateCoordinator->leave();
+    m_privateCoordinator = WTFMove(privateCoordinator);
     m_privateCoordinator->setLogger(m_logger.copyRef(), m_logIdentifier);
     m_privateCoordinator->setClient(makeWeakPtr(this));
+    coordinatorStateChanged(MediaSessionCoordinatorState::Waiting);
 }
 
 MediaSessionCoordinator::~MediaSessionCoordinator() = default;
 
+void MediaSessionCoordinator::eventListenersDidChange()
+{
+    m_hasCoordinatorsStateChangeEventListener = hasEventListeners(eventNames().coordinatorstatechangeEvent);
+}
+
+bool MediaSessionCoordinator::virtualHasPendingActivity() const
+{
+    // Need to keep the JS wrapper alive as long as it may still fire events in the future.
+    return shouldFireEvents();
+}
+
 void MediaSessionCoordinator::join(DOMPromiseDeferred<void>&& promise)
 {
     auto identifier = LOGIDENTIFIER;
@@ -75,6 +101,7 @@
         promise.reject(Exception { InvalidStateError, makeString("Unable to join when state is ", convertEnumerationToString(m_state)) });
         return;
     }
+    ASSERT(m_privateCoordinator, "We must be in Waiting state if no private coordinator is set");
 
     m_privateCoordinator->join([protectedThis = makeRefPtr(*this), identifier, promise = WTFMove(promise)] (std::optional<Exception>&& exception) mutable {
         if (!protectedThis->m_session) {
@@ -88,7 +115,8 @@
             return;
         }
 
-        protectedThis->m_state = MediaSessionCoordinatorState::Joined;
+        protectedThis->coordinatorStateChanged(MediaSessionCoordinatorState::Joined);
+
         promise.resolve();
     });
 }
@@ -107,7 +135,7 @@
 void MediaSessionCoordinator::close()
 {
     ALWAYS_LOG(LOGIDENTIFIER);
-    m_state = MediaSessionCoordinatorState::Closed;
+    coordinatorStateChanged(MediaSessionCoordinatorState::Closed);
     if (!m_privateCoordinator)
         return;
 
@@ -381,6 +409,12 @@
     completionHandler(true);
 }
 
+bool MediaSessionCoordinator::shouldFireEvents() const
+{
+    return m_hasCoordinatorsStateChangeEventListener && m_session;
+}
+
+
 void MediaSessionCoordinator::coordinatorStateChanged(MediaSessionCoordinatorState state)
 {
     if (m_state == state)
@@ -387,6 +421,8 @@
         return;
     m_state = state;
     ALWAYS_LOG(LOGIDENTIFIER, m_state);
+    if (shouldFireEvents())
+        m_asyncEventQueue->enqueueEvent(Event::create(eventNames().coordinatorstatechangeEvent, Event::CanBubble::No, Event::IsCancelable::No));
 }
 
 bool MediaSessionCoordinator::currentPositionApproximatelyEqualTo(double time) const

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.h (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.h	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.h	2021-06-02 01:20:38 UTC (rev 278336)
@@ -27,6 +27,9 @@
 
 #if ENABLE(MEDIA_SESSION_COORDINATOR)
 
+#include "ActiveDOMObject.h"
+#include "EventTarget.h"
+#include "GenericEventQueue.h"
 #include "MediaSession.h"
 #include "MediaSessionCoordinatorPrivate.h"
 #include "MediaSessionCoordinatorState.h"
@@ -41,10 +44,14 @@
 class MediaSessionCoordinator
     : public RefCounted<MediaSessionCoordinator>
     , public MediaSessionCoordinatorClient
-    , public MediaSession::Observer {
+    , public MediaSession::Observer
+    , public ActiveDOMObject
+    , public EventTargetWithInlineData  {
+    WTF_MAKE_FAST_ALLOCATED;
 public:
-    WEBCORE_EXPORT static Ref<MediaSessionCoordinator> create(Ref<MediaSessionCoordinatorPrivate>&&);
+    WEBCORE_EXPORT static Ref<MediaSessionCoordinator> create(ScriptExecutionContext*, RefPtr<MediaSessionCoordinatorPrivate>&&);
     WEBCORE_EXPORT ~MediaSessionCoordinator();
+    WEBCORE_EXPORT void setMediaSessionCoordinatorPrivate(Ref<MediaSessionCoordinatorPrivate>&&);
 
     void join(DOMPromiseDeferred<void>&&);
     ExceptionOr<void> leave();
@@ -62,10 +69,23 @@
 
     using MediaSessionCoordinatorClient::weakPtrFactory;
     using WeakValueType = MediaSessionCoordinatorClient::WeakValueType;
+    using RefCounted::ref;
+    using RefCounted::deref;
 
 private:
-    explicit MediaSessionCoordinator(Ref<MediaSessionCoordinatorPrivate>&&);
+    MediaSessionCoordinator(ScriptExecutionContext*, RefPtr<MediaSessionCoordinatorPrivate>&&);
 
+    // EventTarget
+    void refEventTarget() final { ref(); }
+    void derefEventTarget() final { deref(); }
+    EventTargetInterface eventTargetInterface() const final { return MediaSessionCoordinatorEventTargetInterfaceType; }
+    ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
+    void eventListenersDidChange() final;
+
+    // ActiveDOMObject
+    const char* activeDOMObjectName() const final { return "MediaSessionCoordinator"; }
+    bool virtualHasPendingActivity() const final;
+
     // MediaSession::Observer
     void metadataChanged(const RefPtr<MediaMetadata>&) final;
     void positionStateChanged(const std::optional<MediaPositionState>&) final;
@@ -85,12 +105,15 @@
     const void* logIdentifier() const { return m_logIdentifier; }
     static WTFLogChannel& logChannel();
     static const char* logClassName() { return "MediaSessionCoordinator"; }
+    bool shouldFireEvents() const;
 
     WeakPtr<MediaSession> m_session;
-    MediaSessionCoordinatorState m_state { MediaSessionCoordinatorState::Waiting };
     RefPtr<MediaSessionCoordinatorPrivate> m_privateCoordinator;
-    Ref<const Logger> m_logger;
+    const Ref<const Logger> m_logger;
     const void* m_logIdentifier;
+    UniqueRef<MainThreadGenericEventQueue> m_asyncEventQueue;
+    MediaSessionCoordinatorState m_state { MediaSessionCoordinatorState::Closed };
+    bool m_hasCoordinatorsStateChangeEventListener { false };
 };
 
 }

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.idl (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.idl	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinator.idl	2021-06-02 01:20:38 UTC (rev 278336)
@@ -24,16 +24,20 @@
  */
 
 [
+    ActiveDOMObject,
     Conditional=MEDIA_SESSION_COORDINATOR,
     EnabledBySetting=MediaSessionCoordinator,
     Exposed=Window,
     ExportMacro=WEBCORE_EXPORT,
-] interface MediaSessionCoordinator {
+    JSGenerateToJSObject,
+] interface MediaSessionCoordinator : EventTarget {
 
     Promise<undefined> join();
     undefined leave();
 
     readonly attribute MediaSessionCoordinatorState state;
+    attribute EventHandler oncoordinatorstatechange;
+    
     readonly attribute DOMString? identifier;
 
     Promise<undefined> seekTo(unrestricted double time);

Modified: trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinatorMixin.idl (278335 => 278336)


--- trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinatorMixin.idl	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/Modules/mediasession/MediaSessionCoordinatorMixin.idl	2021-06-02 01:20:38 UTC (rev 278336)
@@ -27,7 +27,6 @@
     Conditional=MEDIA_SESSION_COORDINATOR,
     EnabledBySetting=MediaSessionCoordinator,
 ] interface mixin MediaSessionCoordinatorMixin {
-    readonly attribute MediaSessionCoordinator? coordinator;
-    attribute EventHandler oncoordinatorchange;
+    readonly attribute MediaSessionCoordinator coordinator;
     attribute MediaSessionReadyState readyState;
 };

Modified: trunk/Source/WebCore/dom/EventNames.h (278335 => 278336)


--- trunk/Source/WebCore/dom/EventNames.h	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/dom/EventNames.h	2021-06-02 01:20:38 UTC (rev 278336)
@@ -101,7 +101,7 @@
     macro(connecting) \
     macro(contextmenu) \
     macro(controllerchange) \
-    macro(coordinatorchange) \
+    macro(coordinatorstatechange) \
     macro(copy) \
     macro(cuechange) \
     macro(cut) \

Modified: trunk/Source/WebCore/dom/EventTargetFactory.in (278335 => 278336)


--- trunk/Source/WebCore/dom/EventTargetFactory.in	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/dom/EventTargetFactory.in	2021-06-02 01:20:38 UTC (rev 278336)
@@ -23,7 +23,7 @@
 MediaKeySession conditional=ENCRYPTED_MEDIA
 MediaQueryList
 MediaRecorder conditional=MEDIA_STREAM
-MediaSession conditional=MEDIA_SESSION
+MediaSessionCoordinator conditional=MEDIA_SESSION_COORDINATOR
 MediaSource conditional=MEDIA_SOURCE
 MediaStream conditional=MEDIA_STREAM
 MediaStreamTrack conditional=MEDIA_STREAM

Modified: trunk/Source/WebCore/page/Page.cpp (278335 => 278336)


--- trunk/Source/WebCore/page/Page.cpp	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/page/Page.cpp	2021-06-02 01:20:38 UTC (rev 278336)
@@ -3427,7 +3427,7 @@
 
     auto* window = mainFrame().window();
     if (auto* navigator = window ? window->optionalNavigator() : nullptr)
-        NavigatorMediaSession::mediaSession(*navigator).createCoordinator(*m_mediaSessionCoordinator);
+        NavigatorMediaSession::mediaSession(*navigator).coordinator().setMediaSessionCoordinatorPrivate(*m_mediaSessionCoordinator);
 }
 
 void Page::invalidateMediaSessionCoordinator()
@@ -3441,11 +3441,7 @@
     if (!navigator)
         return;
 
-    auto* coordinator = NavigatorMediaSession::mediaSession(*navigator).coordinator();
-    if (!coordinator)
-        return;
-
-    coordinator->close();
+    NavigatorMediaSession::mediaSession(*navigator).coordinator().close();
 }
 #endif
 

Modified: trunk/Source/WebCore/testing/Internals.cpp (278335 => 278336)


--- trunk/Source/WebCore/testing/Internals.cpp	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Source/WebCore/testing/Internals.cpp	2021-06-02 01:20:38 UTC (rev 278336)
@@ -6246,7 +6246,7 @@
     auto& session = NavigatorMediaSession::mediaSession(document->domWindow()->navigator());
     auto mock = MockMediaSessionCoordinator::create(context, WTFMove(listener));
     m_mockMediaSessionCoordinator = mock.ptr();
-    session.createCoordinator(WTFMove(mock));
+    session.coordinator().setMediaSessionCoordinatorPrivate(WTFMove(mock));
 
     return { };
 }

Modified: trunk/Tools/ChangeLog (278335 => 278336)


--- trunk/Tools/ChangeLog	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Tools/ChangeLog	2021-06-02 01:20:38 UTC (rev 278336)
@@ -1,3 +1,16 @@
+2021-06-01  Jean-Yves Avenard  <[email protected]>
+
+        MediaSession.coordinator should not be optional, relying on coordinator readyState change instead
+        https://bugs.webkit.org/show_bug.cgi?id=226328
+        rdar://77461335
+
+        Reviewed by Eric Carlson.
+
+        * TestWebKitAPI/Tests/WebKit/MediaSessionCoordinatorTest.mm:
+        (TestWebKitAPI::MediaSessionCoordinatorTest::createCoordinator): Change test to match new API,
+        using coordinatorstatechange event instead.
+        * TestWebKitAPI/Tests/WebKitCocoa/media-remote.html:
+
 2021-06-01  Chris Fleizach  <[email protected]>
 
         REGRESSION: (r277971) TestWebKitAPI.WebKit.AccessibilityReduceMotion is timing out

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/MediaSessionCoordinatorTest.mm (278335 => 278336)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/MediaSessionCoordinatorTest.mm	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/MediaSessionCoordinatorTest.mm	2021-06-02 01:20:38 UTC (rev 278336)
@@ -212,14 +212,14 @@
         }];
         TestWebKitAPI::Util::run(&done);
 
-        listenForEventMessages({ "coordinatorchange"_s });
+        listenForEventMessages({ "coordinatorstatechange"_s });
 
         EXPECT_TRUE(result);
         if (!result)
             NSLog(@"-[_createMediaSessionCoordinatorForTesting:completionHandler:] failed!");
 
-        waitForEventListenerToBeCalled("coordinatorchange"_s);
-        ASSERT_TRUE(eventListenerWasCalled("coordinatorchange"_s));
+        waitForEventListenerToBeCalled("coordinatorstatechange"_s);
+        ASSERT_TRUE(eventListenerWasCalled("coordinatorstatechange"_s));
     }
 
     TestWKWebView* webView() const { return _webView.get(); }

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/media-remote.html (278335 => 278336)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/media-remote.html	2021-06-02 01:01:06 UTC (rev 278335)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/media-remote.html	2021-06-02 01:20:38 UTC (rev 278336)
@@ -96,7 +96,7 @@
                 window.webkit.messageHandlers.testHandler.postMessage(message);
         }
 
-        function postEvent(evt) 
+        function postEvent(evt)
         {
             postMessage(`${evt.type} event`);
         }
@@ -135,7 +135,7 @@
             audio.addEventListener('play', postEvent);
             audio.addEventListener('pause', postEvent);
             audio.addEventListener('seeked', postEvent);
-            navigator.mediaSession.addEventListener('coordinatorchange', postEvent);
+            navigator.mediaSession.coordinator.addEventListener('coordinatorstatechange', postEvent);
         }, false);
 
     </script>
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to