Title: [275871] trunk/Source
Revision
275871
Author
commit-qu...@webkit.org
Date
2021-04-13 01:38:14 -0700 (Tue, 13 Apr 2021)

Log Message

[GStreamer] CaptureDevice monitor used from UIProcess
https://bugs.webkit.org/show_bug.cgi?id=222888

Patch by Philippe Normand <pnorm...@igalia.com> on 2021-04-13
Source/WebCore:

Reviewed by Youenn Fablet .

Move the device observer infrastructure from the WebKit UserMediaProcessManager to the
RealtimeMediaSourceCenter.

* platform/mediastream/CaptureDevice.h:
(WebCore::haveDevicesChanged):
* platform/mediastream/RealtimeMediaSourceCenter.cpp:
(WebCore::RealtimeMediaSourceCenter::RealtimeMediaSourceCenter):
(WebCore::RealtimeMediaSourceCenter::Observer::~Observer):
(WebCore::RealtimeMediaSourceCenter::addDevicesChangedObserver):
(WebCore::RealtimeMediaSourceCenter::removeDevicesChangedObserver):
(WebCore::RealtimeMediaSourceCenter::captureDevicesChanged):
(WebCore::RealtimeMediaSourceCenter::triggerDevicesChangedObservers):
(WebCore::RealtimeMediaSourceCenter::setDevicesChangedObserver): Deleted.
* platform/mediastream/RealtimeMediaSourceCenter.h:
(WebCore::RealtimeMediaSourceCenter::Observer::devicesChanged):

Source/WebKit:

Reviewed by Youenn Fablet.

GStreamer ports aim to reduce usage of the GStreamer library in the UIProcess and thus
should not relay capture devicechange monitoring to the UIProcess. For the long term we plan
to migrate media processing to the GPUProcess but for now we have to maintain the media
pipelines in the WebProcess. Initializing GStreamer in multiple processes (including the
UIProcess) has a significant performance impact on embedded platforms, that's why we try to
avoid it as much as possible.

The device monitoring code from the UserMediaProcessManager was partly moved to the
RealtimeMediaSourceCenter so that it can be easily reused by GStreamer ports from the
UserMediaPermissionRequestManager.

* UIProcess/UserMediaProcessManager.cpp:
(WebKit::UserMediaProcessManager::UserMediaProcessManager):
(WebKit::UserMediaProcessManager::updateCaptureDevices):
(WebKit::UserMediaProcessManager::devicesChanged):
(WebKit::UserMediaProcessManager::beginMonitoringCaptureDevices):
* UIProcess/UserMediaProcessManager.h:
* WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
(WebKit::UserMediaPermissionRequestManager::UserMediaPermissionRequestManager):
(WebKit::UserMediaPermissionRequestManager::updateCaptureDevices):
(WebKit::UserMediaPermissionRequestManager::DeviceObserver::devicesChanged):
(WebKit::UserMediaPermissionRequestManager::addDeviceChangeObserver):
* WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
(WebKit::UserMediaPermissionRequestManager::DeviceObserver::DeviceObserver):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (275870 => 275871)


--- trunk/Source/WebCore/ChangeLog	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebCore/ChangeLog	2021-04-13 08:38:14 UTC (rev 275871)
@@ -1,3 +1,26 @@
+2021-04-13  Philippe Normand  <pnorm...@igalia.com>
+
+        [GStreamer] CaptureDevice monitor used from UIProcess
+        https://bugs.webkit.org/show_bug.cgi?id=222888
+
+        Reviewed by Youenn Fablet .
+
+        Move the device observer infrastructure from the WebKit UserMediaProcessManager to the
+        RealtimeMediaSourceCenter.
+
+        * platform/mediastream/CaptureDevice.h:
+        (WebCore::haveDevicesChanged):
+        * platform/mediastream/RealtimeMediaSourceCenter.cpp:
+        (WebCore::RealtimeMediaSourceCenter::RealtimeMediaSourceCenter):
+        (WebCore::RealtimeMediaSourceCenter::Observer::~Observer):
+        (WebCore::RealtimeMediaSourceCenter::addDevicesChangedObserver):
+        (WebCore::RealtimeMediaSourceCenter::removeDevicesChangedObserver):
+        (WebCore::RealtimeMediaSourceCenter::captureDevicesChanged):
+        (WebCore::RealtimeMediaSourceCenter::triggerDevicesChangedObservers):
+        (WebCore::RealtimeMediaSourceCenter::setDevicesChangedObserver): Deleted.
+        * platform/mediastream/RealtimeMediaSourceCenter.h:
+        (WebCore::RealtimeMediaSourceCenter::Observer::devicesChanged):
+
 2021-04-13  Antoine Quint  <grao...@webkit.org>
 
         calc() simplification for a multiplication should apply the multiplication to each value of an addition

Modified: trunk/Source/WebCore/platform/mediastream/CaptureDevice.h (275870 => 275871)


--- trunk/Source/WebCore/platform/mediastream/CaptureDevice.h	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebCore/platform/mediastream/CaptureDevice.h	2021-04-13 08:38:14 UTC (rev 275871)
@@ -140,6 +140,26 @@
     bool m_isMockDevice { false };
 };
 
+inline bool haveDevicesChanged(const Vector<CaptureDevice>& oldDevices, const Vector<CaptureDevice>& newDevices)
+{
+    if (oldDevices.size() != newDevices.size())
+        return true;
+
+    for (auto& newDevice : newDevices) {
+        if (newDevice.type() != CaptureDevice::DeviceType::Camera && newDevice.type() != CaptureDevice::DeviceType::Microphone)
+            continue;
+
+        auto index = oldDevices.findMatching([&newDevice](auto& oldDevice) {
+            return newDevice.persistentId() == oldDevice.persistentId() && newDevice.enabled() != oldDevice.enabled();
+        });
+
+        if (index == notFound)
+            return true;
+    }
+
+    return false;
+}
+
 } // namespace WebCore
 
 #if ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp (275870 => 275871)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp	2021-04-13 08:38:14 UTC (rev 275871)
@@ -42,6 +42,8 @@
 
 namespace WebCore {
 
+static const Seconds deviceChangeDebounceTimerInterval { 200_ms };
+
 RealtimeMediaSourceCenter& RealtimeMediaSourceCenter::singleton()
 {
     ASSERT(isMainThread());
@@ -50,6 +52,7 @@
 }
 
 RealtimeMediaSourceCenter::RealtimeMediaSourceCenter()
+    : m_debounceTimer(RunLoop::main(), this, &RealtimeMediaSourceCenter::triggerDevicesChangedObservers)
 {
     m_supportedConstraints.setSupportsEchoCancellation(true);
     m_supportedConstraints.setSupportsWidth(true);
@@ -63,6 +66,8 @@
 
 RealtimeMediaSourceCenter::~RealtimeMediaSourceCenter() = default;
 
+RealtimeMediaSourceCenter::Observer::~Observer() = default;
+
 void RealtimeMediaSourceCenter::createMediaStream(Ref<const Logger>&& logger, NewMediaStreamHandler&& completionHandler, String&& hashSalt, CaptureDevice&& audioDevice, CaptureDevice&& videoDevice, const MediaStreamRequest& request)
 {
     Vector<Ref<RealtimeMediaSource>> audioSources;
@@ -188,20 +193,36 @@
     return SHA1::hexDigest(digest).data();
 }
 
-void RealtimeMediaSourceCenter::setDevicesChangedObserver(std::function<void()>&& observer)
+void RealtimeMediaSourceCenter::addDevicesChangedObserver(Observer& observer)
 {
     ASSERT(isMainThread());
-    ASSERT(!m_deviceChangedObserver);
-    m_deviceChangedObserver = WTFMove(observer);
+    m_observers.add(observer);
 }
 
+void RealtimeMediaSourceCenter::removeDevicesChangedObserver(Observer& observer)
+{
+    ASSERT(isMainThread());
+    m_observers.remove(observer);
+}
+
 void RealtimeMediaSourceCenter::captureDevicesChanged()
 {
     ASSERT(isMainThread());
-    if (m_deviceChangedObserver)
-        m_deviceChangedObserver();
+
+    // When a device with camera and microphone is attached or detached, the CaptureDevice notification for
+    // the different devices won't arrive at the same time so delay a bit so we can coalesce the callbacks.
+    if (!m_debounceTimer.isActive())
+        m_debounceTimer.startOneShot(deviceChangeDebounceTimerInterval);
 }
 
+void RealtimeMediaSourceCenter::triggerDevicesChangedObservers()
+{
+    auto protectedThis = makeRef(*this);
+    m_observers.forEach([](auto& observer) {
+        observer.devicesChanged();
+    });
+}
+
 void RealtimeMediaSourceCenter::getDisplayMediaDevices(const MediaStreamRequest& request, Vector<DeviceInfo>& diaplayDeviceInfo, String& firstInvalidConstraint)
 {
     if (!request.videoConstraints.isValid)

Modified: trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h (275870 => 275871)


--- trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h	2021-04-13 08:38:14 UTC (rev 275871)
@@ -39,8 +39,10 @@
 #include "RealtimeMediaSource.h"
 #include "RealtimeMediaSourceFactory.h"
 #include "RealtimeMediaSourceSupportedConstraints.h"
+#include "UserMediaClient.h"
 #include <wtf/Function.h>
 #include <wtf/RefPtr.h>
+#include <wtf/RunLoop.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -52,9 +54,16 @@
 class TrackSourceInfo;
 
 struct MediaConstraints;
-    
-class RealtimeMediaSourceCenter {
+
+class WEBCORE_EXPORT RealtimeMediaSourceCenter : public ThreadSafeRefCounted<RealtimeMediaSourceCenter, WTF::DestructionThread::MainRunLoop> {
 public:
+    class Observer : public CanMakeWeakPtr<Observer> {
+    public:
+        virtual ~Observer();
+
+        virtual void devicesChanged() = 0;
+    };
+
     ~RealtimeMediaSourceCenter();
 
     WEBCORE_EXPORT static RealtimeMediaSourceCenter& singleton();
@@ -84,7 +93,8 @@
 
     WEBCORE_EXPORT String hashStringWithSalt(const String& id, const String& hashSalt);
 
-    WEBCORE_EXPORT void setDevicesChangedObserver(std::function<void()>&&);
+    WEBCORE_EXPORT void addDevicesChangedObserver(Observer&);
+    WEBCORE_EXPORT void removeDevicesChangedObserver(Observer&);
 
     void captureDevicesChanged();
 
@@ -108,8 +118,11 @@
 
     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
 
-    WTF::Function<void()> m_deviceChangedObserver;
+    RunLoop::Timer<RealtimeMediaSourceCenter> m_debounceTimer;
+    void triggerDevicesChangedObservers();
 
+    WeakHashSet<Observer> m_observers;
+
     AudioCaptureFactory* m_audioCaptureFactoryOverride { nullptr };
     VideoCaptureFactory* m_videoCaptureFactoryOverride { nullptr };
     DisplayCaptureFactory* m_displayCaptureFactoryOverride { nullptr };

Modified: trunk/Source/WebKit/ChangeLog (275870 => 275871)


--- trunk/Source/WebKit/ChangeLog	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebKit/ChangeLog	2021-04-13 08:38:14 UTC (rev 275871)
@@ -1,3 +1,35 @@
+2021-04-13  Philippe Normand  <pnorm...@igalia.com>
+
+        [GStreamer] CaptureDevice monitor used from UIProcess
+        https://bugs.webkit.org/show_bug.cgi?id=222888
+
+        Reviewed by Youenn Fablet.
+
+        GStreamer ports aim to reduce usage of the GStreamer library in the UIProcess and thus
+        should not relay capture devicechange monitoring to the UIProcess. For the long term we plan
+        to migrate media processing to the GPUProcess but for now we have to maintain the media
+        pipelines in the WebProcess. Initializing GStreamer in multiple processes (including the
+        UIProcess) has a significant performance impact on embedded platforms, that's why we try to
+        avoid it as much as possible.
+
+        The device monitoring code from the UserMediaProcessManager was partly moved to the
+        RealtimeMediaSourceCenter so that it can be easily reused by GStreamer ports from the
+        UserMediaPermissionRequestManager.
+
+        * UIProcess/UserMediaProcessManager.cpp:
+        (WebKit::UserMediaProcessManager::UserMediaProcessManager):
+        (WebKit::UserMediaProcessManager::updateCaptureDevices):
+        (WebKit::UserMediaProcessManager::devicesChanged):
+        (WebKit::UserMediaProcessManager::beginMonitoringCaptureDevices):
+        * UIProcess/UserMediaProcessManager.h:
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp:
+        (WebKit::UserMediaPermissionRequestManager::UserMediaPermissionRequestManager):
+        (WebKit::UserMediaPermissionRequestManager::updateCaptureDevices):
+        (WebKit::UserMediaPermissionRequestManager::DeviceObserver::devicesChanged):
+        (WebKit::UserMediaPermissionRequestManager::addDeviceChangeObserver):
+        * WebProcess/MediaStream/UserMediaPermissionRequestManager.h:
+        (WebKit::UserMediaPermissionRequestManager::DeviceObserver::DeviceObserver):
+
 2021-04-12  Julian Gonzalez  <julian_a_gonza...@apple.com>
 
         [CoreIPC] Crash in logDiagnosticMessage code

Modified: trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp (275870 => 275871)


--- trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebKit/UIProcess/UserMediaProcessManager.cpp	2021-04-13 08:38:14 UTC (rev 275871)
@@ -27,7 +27,6 @@
 #include "WebPageProxy.h"
 #include "WebProcessMessages.h"
 #include "WebProcessProxy.h"
-#include <WebCore/RealtimeMediaSourceCenter.h>
 #include <wtf/HashMap.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/TranslatedProcess.h>
@@ -41,8 +40,6 @@
 static const ASCIILiteral additionalAppleCameraServicePath { "com.apple.appleh13camerad"_s };
 #endif
 
-static const Seconds deviceChangeDebounceTimerInterval { 200_ms };
-
 UserMediaProcessManager& UserMediaProcessManager::singleton()
 {
     static NeverDestroyed<UserMediaProcessManager> manager;
@@ -50,7 +47,6 @@
 }
 
 UserMediaProcessManager::UserMediaProcessManager()
-    : m_debounceTimer(RunLoop::main(), this, &UserMediaProcessManager::captureDevicesChanged)
 {
 }
 
@@ -216,40 +212,24 @@
 
 void UserMediaProcessManager::updateCaptureDevices(ShouldNotify shouldNotify)
 {
-    WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices([this, shouldNotify] (auto&& newDevices) mutable {
-        auto oldDevices = WTFMove(m_captureDevices);
-        m_captureDevices = WTFMove(newDevices);
+    WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices([weakThis = makeWeakPtr(*this), this, shouldNotify](auto&& newDevices) mutable {
+        if (!weakThis)
+            return;
 
-        if (shouldNotify == ShouldNotify::No)
+        if (!haveDevicesChanged(m_captureDevices, newDevices))
             return;
 
-        if (m_captureDevices.size() == oldDevices.size()) {
-            bool haveChanges = false;
-            for (auto &newDevice : m_captureDevices) {
-                if (newDevice.type() != WebCore::CaptureDevice::DeviceType::Camera && newDevice.type() != WebCore::CaptureDevice::DeviceType::Microphone)
-                    continue;
-
-                auto index = oldDevices.findMatching([&newDevice] (auto& oldDevice) {
-                    return newDevice.persistentId() == oldDevice.persistentId() && newDevice.enabled() != oldDevice.enabled();
-                });
-
-                if (index == notFound) {
-                    haveChanges = true;
-                    break;
-                }
-            }
-
-            if (!haveChanges)
-                return;
-        }
-
-        // When a device with camera and microphone is attached or detached, the CaptureDevice notification for
-        // the different devices won't arrive at the same time so delay a bit so we can coalesce the callbacks.
-        if (!m_debounceTimer.isActive())
-            m_debounceTimer.startOneShot(deviceChangeDebounceTimerInterval);
+        m_captureDevices = WTFMove(newDevices);
+        if (shouldNotify == ShouldNotify::Yes)
+            captureDevicesChanged();
     });
 }
 
+void UserMediaProcessManager::devicesChanged()
+{
+    updateCaptureDevices(ShouldNotify::Yes);
+}
+
 void UserMediaProcessManager::beginMonitoringCaptureDevices()
 {
     static std::once_flag onceFlag;
@@ -256,10 +236,7 @@
 
     std::call_once(onceFlag, [this] {
         updateCaptureDevices(ShouldNotify::No);
-
-        WebCore::RealtimeMediaSourceCenter::singleton().setDevicesChangedObserver([this]() {
-            updateCaptureDevices(ShouldNotify::Yes);
-        });
+        WebCore::RealtimeMediaSourceCenter::singleton().addDevicesChangedObserver(*this);
     });
 }
 

Modified: trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h (275870 => 275871)


--- trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebKit/UIProcess/UserMediaProcessManager.h	2021-04-13 08:38:14 UTC (rev 275871)
@@ -23,13 +23,15 @@
 #include "UserMediaPermissionRequestManagerProxy.h"
 #include <WebCore/CaptureDevice.h>
 #include <WebCore/PageIdentifier.h>
-#include <wtf/RunLoop.h>
+#include <WebCore/RealtimeMediaSourceCenter.h>
+#include <WebCore/UserMediaClient.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebKit {
 
 class WebProcessProxy;
 
-class UserMediaProcessManager {
+class UserMediaProcessManager : public WebCore::RealtimeMediaSourceCenter::Observer {
 public:
 
     static UserMediaProcessManager& singleton();
@@ -48,12 +50,14 @@
     void beginMonitoringCaptureDevices();
 
 private:
-    enum class ShouldNotify { Yes, No };
+    enum class ShouldNotify : bool { No, Yes };
     void updateCaptureDevices(ShouldNotify);
     void captureDevicesChanged();
 
+    // RealtimeMediaSourceCenter::Observer
+    void devicesChanged() final;
+
     Vector<WebCore::CaptureDevice> m_captureDevices;
-    RunLoop::Timer<UserMediaProcessManager> m_debounceTimer;
     bool m_captureEnabled { true };
     bool m_denyNextRequest { false };
 };

Modified: trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp (275870 => 275871)


--- trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.cpp	2021-04-13 08:38:14 UTC (rev 275871)
@@ -148,6 +148,28 @@
     m_page.sendWithAsyncReply(Messages::WebPageProxy::EnumerateMediaDevicesForFrame { WebFrame::fromCoreFrame(*frame)->frameID(), document.securityOrigin().data(), document.topOrigin().data() }, WTFMove(completionHandler));
 }
 
+#if USE(GSTREAMER)
+void UserMediaPermissionRequestManager::updateCaptureDevices(ShouldNotify shouldNotify)
+{
+    WebCore::RealtimeMediaSourceCenter::singleton().getMediaStreamDevices([weakThis = makeWeakPtr(*this), this, shouldNotify](auto&& newDevices) mutable {
+        if (!weakThis)
+            return;
+
+        if (!haveDevicesChanged(m_captureDevices, newDevices))
+            return;
+
+        m_captureDevices = WTFMove(newDevices);
+        if (shouldNotify == ShouldNotify::Yes)
+            captureDevicesChanged();
+    });
+}
+
+void UserMediaPermissionRequestManager::devicesChanged()
+{
+    updateCaptureDevices(ShouldNotify::Yes);
+}
+#endif
+
 UserMediaClient::DeviceChangeObserverToken UserMediaPermissionRequestManager::addDeviceChangeObserver(Function<void()>&& observer)
 {
     auto identifier = UserMediaClient::DeviceChangeObserverToken::generate();
@@ -155,7 +177,12 @@
 
     if (!m_monitoringDeviceChange) {
         m_monitoringDeviceChange = true;
+#if USE(GSTREAMER)
+        updateCaptureDevices(ShouldNotify::No);
+        WebCore::RealtimeMediaSourceCenter::singleton().addDevicesChangedObserver(*this);
+#else
         m_page.send(Messages::WebPageProxy::BeginMonitoringCaptureDevices());
+#endif
     }
     return identifier;
 }

Modified: trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h (275870 => 275871)


--- trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h	2021-04-13 08:34:49 UTC (rev 275870)
+++ trunk/Source/WebKit/WebProcess/MediaStream/UserMediaPermissionRequestManager.h	2021-04-13 08:38:14 UTC (rev 275871)
@@ -24,6 +24,7 @@
 #include "SandboxExtension.h"
 #include <WebCore/MediaCanStartListener.h>
 #include <WebCore/MediaConstraints.h>
+#include <WebCore/RealtimeMediaSourceCenter.h>
 #include <WebCore/UserMediaClient.h>
 #include <WebCore/UserMediaRequest.h>
 #include <wtf/HashMap.h>
@@ -34,9 +35,16 @@
 
 class WebPage;
 
-class UserMediaPermissionRequestManager : private WebCore::MediaCanStartListener {
+class UserMediaPermissionRequestManager : public WebCore::MediaCanStartListener
+#if USE(GSTREAMER)
+                                        , public WebCore::RealtimeMediaSourceCenter::Observer
+#endif
+{
     WTF_MAKE_FAST_ALLOCATED;
 public:
+    using WebCore::MediaCanStartListener::weakPtrFactory;
+    using WeakValueType = WebCore::MediaCanStartListener::WeakValueType;
+
     explicit UserMediaPermissionRequestManager(WebPage&);
     ~UserMediaPermissionRequestManager() = default;
 
@@ -53,6 +61,11 @@
     void captureDevicesChanged();
 
 private:
+#if USE(GSTREAMER)
+    // WebCore::RealtimeMediaSourceCenter::Observer
+    void devicesChanged() final;
+#endif
+
     void sendUserMediaRequest(WebCore::UserMediaRequest&);
 
     // WebCore::MediaCanStartListener
@@ -65,6 +78,13 @@
 
     HashMap<WebCore::UserMediaClient::DeviceChangeObserverToken, Function<void()>> m_deviceChangeObserverMap;
     bool m_monitoringDeviceChange { false };
+
+#if USE(GSTREAMER)
+    enum class ShouldNotify : bool { No, Yes };
+    void updateCaptureDevices(ShouldNotify);
+
+    Vector<WebCore::CaptureDevice> m_captureDevices;
+#endif
 };
 
 } // namespace WebKit
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to