[GStreamer] Do not use GThreadSafeMainLoopSource to send notifications to the main...
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Nov 2015 12:56:02 +0000 (12:56 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Nov 2015 12:56:02 +0000 (12:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150888

Reviewed by Žan Doberšek.

Analyzing how the main loop sources were used in GST code I've
noticed that in most of the cases they are used to send
notifications to the main thread. The way it works in those cases
is that some state is updated in whatever thread and we notify the
main thread to use the new state. There's no data passed to the
main thread, they are just notifications. I've also noticed that
we are not doing this exactly as expected in several of those
cases. GThreadSafeMainLoopSource cancels the current source when a
new one is scheduled, and that was done this way because previous
code in GST using GSources directly did it that way. But that's
not what we want, if there's a notification pending, since the
state is updated, we can just wait for it to happen instead of
cancelling and scheduling a new one. I've also noticed that in
most of the cases where we schedule notifications to the main
thread, we can be already in the main thread, so we could avoid
the schedule entirely.
We can use RunLoop::dispatch() to send notifications to the main
thread, but there's no way to cancel those tasks. This patch adds
a new helper class MainThreadNotifier that uses an enum of flags to
handle different kind of notifications. It uses
RunLoop::dispatch() to send notifications to the main thread, but
only if there isn't one pending for the given type.
This patch also makes signal callbacks static members to be able
to make the private methods actually private.

* platform/graphics/gstreamer/MainThreadNotifier.h: Added.
(WebCore::MainThreadNotifier::MainThreadNotifier):
(WebCore::MainThreadNotifier::notify):
(WebCore::MainThreadNotifier::cancelPendingNotifications):
(WebCore::MainThreadNotifier::addPendingNotification):
(WebCore::MainThreadNotifier::removePendingNotification):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::setAudioStreamPropertiesCallback):
(WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
(WebCore::MediaPlayerPrivateGStreamer::videoChangedCallback):
(WebCore::MediaPlayerPrivateGStreamer::videoSinkCapsChangedCallback):
(WebCore::MediaPlayerPrivateGStreamer::audioChangedCallback):
(WebCore::MediaPlayerPrivateGStreamer::textChangedCallback):
(WebCore::MediaPlayerPrivateGStreamer::newTextSampleCallback):
(WebCore::MediaPlayerPrivateGStreamer::sourceChangedCallback):
(WebCore::MediaPlayerPrivateGStreamer::createAudioSink):
(WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
(WebCore::MediaPlayerPrivateGStreamer::setAudioStreamProperties): Deleted.
(WebCore::MediaPlayerPrivateGStreamer::registerMediaEngine): Deleted.
(WebCore::initializeGStreamerAndRegisterWebKitElements): Deleted.
(WebCore::MediaPlayerPrivateGStreamer::load): Deleted.
(WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfVideo): Deleted.
(WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfAudio): Deleted.
(WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfText): Deleted.
(WebCore::MediaPlayerPrivateGStreamer::canSaveMediaData): Deleted.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
(WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
(WebCore::MediaPlayerPrivateGStreamerBase::volumeChangedCallback):
(WebCore::MediaPlayerPrivateGStreamerBase::muteChangedCallback):
(WebCore::MediaPlayerPrivateGStreamerBase::repaintCallback):
(WebCore::MediaPlayerPrivateGStreamerBase::drawCallback):
(WebCore::MediaPlayerPrivateGStreamerBase::createVideoSink):
(WebCore::MediaPlayerPrivateGStreamerBase::setStreamVolumeElement):
(WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase): Deleted.
(WebCore::MediaPlayerPrivateGStreamerBase::setPipeline): Deleted.
(WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage): Deleted.
(WebCore::MediaPlayerPrivateGStreamerBase::muted): Deleted.
(WebCore::MediaPlayerPrivateGStreamerBase::updateTexture): Deleted.
(WebCore::MediaPlayerPrivateGStreamerBase::droppedFrameCount): Deleted.
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
(WebCore::MediaPlayerPrivateGStreamerBase::setVisible): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@192099 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h [new file with mode: 0644]
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp
Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h

index daeac15..003f0db 100644 (file)
@@ -1,3 +1,78 @@
+2015-11-06  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GStreamer] Do not use GThreadSafeMainLoopSource to send notifications to the main thread in MediaPlayerPrivateGStreamer
+        https://bugs.webkit.org/show_bug.cgi?id=150888
+
+        Reviewed by Žan Doberšek.
+
+        Analyzing how the main loop sources were used in GST code I've
+        noticed that in most of the cases they are used to send
+        notifications to the main thread. The way it works in those cases
+        is that some state is updated in whatever thread and we notify the
+        main thread to use the new state. There's no data passed to the
+        main thread, they are just notifications. I've also noticed that
+        we are not doing this exactly as expected in several of those
+        cases. GThreadSafeMainLoopSource cancels the current source when a
+        new one is scheduled, and that was done this way because previous
+        code in GST using GSources directly did it that way. But that's
+        not what we want, if there's a notification pending, since the
+        state is updated, we can just wait for it to happen instead of
+        cancelling and scheduling a new one. I've also noticed that in
+        most of the cases where we schedule notifications to the main
+        thread, we can be already in the main thread, so we could avoid
+        the schedule entirely.
+        We can use RunLoop::dispatch() to send notifications to the main
+        thread, but there's no way to cancel those tasks. This patch adds
+        a new helper class MainThreadNotifier that uses an enum of flags to
+        handle different kind of notifications. It uses
+        RunLoop::dispatch() to send notifications to the main thread, but
+        only if there isn't one pending for the given type.
+        This patch also makes signal callbacks static members to be able
+        to make the private methods actually private.
+
+        * platform/graphics/gstreamer/MainThreadNotifier.h: Added.
+        (WebCore::MainThreadNotifier::MainThreadNotifier):
+        (WebCore::MainThreadNotifier::notify):
+        (WebCore::MainThreadNotifier::cancelPendingNotifications):
+        (WebCore::MainThreadNotifier::addPendingNotification):
+        (WebCore::MainThreadNotifier::removePendingNotification):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::setAudioStreamPropertiesCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
+        (WebCore::MediaPlayerPrivateGStreamer::videoChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::videoSinkCapsChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::audioChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::textChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::newTextSampleCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::sourceChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamer::createAudioSink):
+        (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
+        (WebCore::MediaPlayerPrivateGStreamer::setAudioStreamProperties): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamer::registerMediaEngine): Deleted.
+        (WebCore::initializeGStreamerAndRegisterWebKitElements): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamer::load): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfVideo): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfAudio): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamer::notifyPlayerOfText): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamer::canSaveMediaData): Deleted.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp:
+        (WebCore::MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase):
+        (WebCore::MediaPlayerPrivateGStreamerBase::volumeChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamerBase::muteChangedCallback):
+        (WebCore::MediaPlayerPrivateGStreamerBase::repaintCallback):
+        (WebCore::MediaPlayerPrivateGStreamerBase::drawCallback):
+        (WebCore::MediaPlayerPrivateGStreamerBase::createVideoSink):
+        (WebCore::MediaPlayerPrivateGStreamerBase::setStreamVolumeElement):
+        (WebCore::MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamerBase::setPipeline): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamerBase::handleSyncMessage): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamerBase::muted): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamerBase::updateTexture): Deleted.
+        (WebCore::MediaPlayerPrivateGStreamerBase::droppedFrameCount): Deleted.
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.h:
+        (WebCore::MediaPlayerPrivateGStreamerBase::setVisible): Deleted.
+
 2015-11-06  Yoav Weiss  <yoav@yoav.ws>
 
         Expose HTMLImageElement sizes attribute in IDL
 2015-11-06  Yoav Weiss  <yoav@yoav.ws>
 
         Expose HTMLImageElement sizes attribute in IDL
diff --git a/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h b/Source/WebCore/platform/graphics/gstreamer/MainThreadNotifier.h
new file mode 100644 (file)
index 0000000..862c419
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (C) 2015 Igalia S.L
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef MainThreadNotifier_h
+#define MainThreadNotifier_h
+
+#include <wtf/Lock.h>
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+template <typename T>
+class MainThreadNotifier {
+public:
+    MainThreadNotifier()
+        : m_weakPtrFactory(this)
+    {
+    }
+
+    template<typename F>
+    void notify(T notificationType, const F& callbackFunctor)
+    {
+        if (isMainThread()) {
+            removePendingNotification(notificationType);
+            callbackFunctor();
+            return;
+        }
+
+        if (!addPendingNotification(notificationType))
+            return;
+
+        auto weakThis = m_weakPtrFactory.createWeakPtr();
+        std::function<void ()> callback(callbackFunctor);
+        RunLoop::main().dispatch([weakThis, notificationType, callback] {
+            if (weakThis && weakThis->removePendingNotification(notificationType))
+                callback();
+        });
+    }
+
+    void cancelPendingNotifications(unsigned mask = 0)
+    {
+        LockHolder locker(m_pendingNotificationsLock);
+        if (mask)
+            m_pendingNotifications &= ~mask;
+        else
+            m_pendingNotifications = 0;
+    }
+
+private:
+
+    bool addPendingNotification(T notificationType)
+    {
+        LockHolder locker(m_pendingNotificationsLock);
+        if (notificationType & m_pendingNotifications)
+            return false;
+        m_pendingNotifications |= notificationType;
+        return true;
+    }
+
+    bool removePendingNotification(T notificationType)
+    {
+        LockHolder locker(m_pendingNotificationsLock);
+        if (notificationType & m_pendingNotifications) {
+            m_pendingNotifications &= ~notificationType;
+            return true;
+        }
+        return false;
+    }
+
+    WeakPtrFactory<MainThreadNotifier> m_weakPtrFactory;
+    Lock m_pendingNotificationsLock;
+    unsigned m_pendingNotifications { 0 };
+};
+
+
+} // namespace WebCore
+
+#endif // MainThreadNotifier_h
index 17b22a6..329c21b 100644 (file)
@@ -76,45 +76,11 @@ using namespace std;
 
 namespace WebCore {
 
 
 namespace WebCore {
 
-static void mediaPlayerPrivateSourceChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
-{
-    player->sourceChanged();
-}
-
-static void mediaPlayerPrivateVideoSinkCapsChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamer* player)
-{
-    player->videoCapsChanged();
-}
-
-static void mediaPlayerPrivateVideoChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
-{
-    player->videoChanged();
-}
-
-static void mediaPlayerPrivateAudioChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
-{
-    player->audioChanged();
-}
-
-static void setAudioStreamPropertiesCallback(GstChildProxy*, GObject* object, gchar*,
-    MediaPlayerPrivateGStreamer* player)
+void MediaPlayerPrivateGStreamer::setAudioStreamPropertiesCallback(MediaPlayerPrivateGStreamer* player, GObject* object)
 {
     player->setAudioStreamProperties(object);
 }
 
 {
     player->setAudioStreamProperties(object);
 }
 
-#if ENABLE(VIDEO_TRACK)
-static void mediaPlayerPrivateTextChangedCallback(GObject*, MediaPlayerPrivateGStreamer* player)
-{
-    player->textChanged();
-}
-
-static GstFlowReturn mediaPlayerPrivateNewTextSampleCallback(GObject*, MediaPlayerPrivateGStreamer* player)
-{
-    player->newTextSample();
-    return GST_FLOW_OK;
-}
-#endif
-
 void MediaPlayerPrivateGStreamer::setAudioStreamProperties(GObject* object)
 {
     if (g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink"))
 void MediaPlayerPrivateGStreamer::setAudioStreamProperties(GObject* object)
 {
     if (g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink"))
@@ -244,21 +210,13 @@ MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer()
         GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
         ASSERT(bus);
         gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
         GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
         ASSERT(bus);
         gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
-
-        g_signal_handlers_disconnect_by_func(m_pipeline.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateSourceChangedCallback), this);
-        g_signal_handlers_disconnect_by_func(m_pipeline.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoChangedCallback), this);
-        g_signal_handlers_disconnect_by_func(m_pipeline.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateAudioChangedCallback), this);
-#if ENABLE(VIDEO_TRACK)
-        g_signal_handlers_disconnect_by_func(m_pipeline.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateNewTextSampleCallback), this);
-        g_signal_handlers_disconnect_by_func(m_pipeline.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateTextChangedCallback), this);
-#endif
-
+        g_signal_handlers_disconnect_matched(m_pipeline.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
         gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
     }
 
     if (m_videoSink) {
         GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_videoSink.get(), "sink"));
         gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
     }
 
     if (m_videoSink) {
         GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_videoSink.get(), "sink"));
-        g_signal_handlers_disconnect_by_func(videoSinkPad.get(), reinterpret_cast<gpointer>(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
+        g_signal_handlers_disconnect_by_func(videoSinkPad.get(), reinterpret_cast<gpointer>(videoSinkCapsChangedCallback), this);
     }
 }
 
     }
 }
 
@@ -649,16 +607,9 @@ bool MediaPlayerPrivateGStreamer::seeking() const
     return m_seeking;
 }
 
     return m_seeking;
 }
 
-void MediaPlayerPrivateGStreamer::videoChanged()
+void MediaPlayerPrivateGStreamer::videoChangedCallback(MediaPlayerPrivateGStreamer* player)
 {
 {
-    m_videoTimerHandler.schedule("[WebKit] MediaPlayerPrivateGStreamer::videoChanged",
-        std::function<void()>([this] { notifyPlayerOfVideo(); }));
-}
-
-void MediaPlayerPrivateGStreamer::videoCapsChanged()
-{
-    m_videoCapsTimerHandler.schedule("[WebKit] MediaPlayerPrivateGStreamer::videoCapsChanged",
-        std::function<void()>([this] { notifyPlayerOfVideoCaps(); }));
+    player->m_notifier.notify(MainThreadNotification::VideoChanged, [player] { player->notifyPlayerOfVideo(); });
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
@@ -698,16 +649,20 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfVideo()
     m_player->client().mediaPlayerEngineUpdated(m_player);
 }
 
     m_player->client().mediaPlayerEngineUpdated(m_player);
 }
 
+void MediaPlayerPrivateGStreamer::videoSinkCapsChangedCallback(MediaPlayerPrivateGStreamer* player)
+{
+    player->m_notifier.notify(MainThreadNotification::VideoCapsChanged, [player] { player->notifyPlayerOfVideoCaps(); });
+}
+
 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoCaps()
 {
     m_videoSize = IntSize();
     m_player->client().mediaPlayerEngineUpdated(m_player);
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfVideoCaps()
 {
     m_videoSize = IntSize();
     m_player->client().mediaPlayerEngineUpdated(m_player);
 }
 
-void MediaPlayerPrivateGStreamer::audioChanged()
+void MediaPlayerPrivateGStreamer::audioChangedCallback(MediaPlayerPrivateGStreamer* player)
 {
 {
-    m_audioTimerHandler.schedule("[WebKit] MediaPlayerPrivateGStreamer::audioChanged",
-        std::function<void()>([this] { notifyPlayerOfAudio(); }));
+    player->m_notifier.notify(MainThreadNotification::AudioChanged, [player] { player->notifyPlayerOfAudio(); });
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
@@ -748,10 +703,9 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfAudio()
 }
 
 #if ENABLE(VIDEO_TRACK)
 }
 
 #if ENABLE(VIDEO_TRACK)
-void MediaPlayerPrivateGStreamer::textChanged()
+void MediaPlayerPrivateGStreamer::textChangedCallback(MediaPlayerPrivateGStreamer* player)
 {
 {
-    m_textTimerHandler.schedule("[WebKit] MediaPlayerPrivateGStreamer::textChanged",
-        std::function<void()>([this] { notifyPlayerOfText(); }));
+    player->m_notifier.notify(MainThreadNotification::TextChanged, [player] { player->notifyPlayerOfText(); });
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
 }
 
 void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
@@ -785,6 +739,12 @@ void MediaPlayerPrivateGStreamer::notifyPlayerOfText()
     }
 }
 
     }
 }
 
+GstFlowReturn MediaPlayerPrivateGStreamer::newTextSampleCallback(MediaPlayerPrivateGStreamer* player)
+{
+    player->newTextSample();
+    return GST_FLOW_OK;
+}
+
 void MediaPlayerPrivateGStreamer::newTextSample()
 {
     if (!m_textAppSink)
 void MediaPlayerPrivateGStreamer::newTextSample()
 {
     if (!m_textAppSink)
@@ -1318,6 +1278,11 @@ unsigned long long MediaPlayerPrivateGStreamer::totalBytes() const
     return m_totalBytes;
 }
 
     return m_totalBytes;
 }
 
+void MediaPlayerPrivateGStreamer::sourceChangedCallback(MediaPlayerPrivateGStreamer* player)
+{
+    player->sourceChanged();
+}
+
 void MediaPlayerPrivateGStreamer::sourceChanged()
 {
     m_source.clear();
 void MediaPlayerPrivateGStreamer::sourceChanged()
 {
     m_source.clear();
@@ -1868,7 +1833,7 @@ GstElement* MediaPlayerPrivateGStreamer::createAudioSink()
         return nullptr;
     }
 
         return nullptr;
     }
 
-    g_signal_connect(m_autoAudioSink.get(), "child-added", G_CALLBACK(setAudioStreamPropertiesCallback), this);
+    g_signal_connect_swapped(m_autoAudioSink.get(), "child-added", G_CALLBACK(setAudioStreamPropertiesCallback), this);
 
     GstElement* audioSinkBin;
 
 
     GstElement* audioSinkBin;
 
@@ -1960,12 +1925,12 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin()
 
     g_object_set(m_pipeline.get(), "mute", m_player->muted(), nullptr);
 
 
     g_object_set(m_pipeline.get(), "mute", m_player->muted(), nullptr);
 
-    g_signal_connect(m_pipeline.get(), "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
-    g_signal_connect(m_pipeline.get(), "video-changed", G_CALLBACK(mediaPlayerPrivateVideoChangedCallback), this);
-    g_signal_connect(m_pipeline.get(), "audio-changed", G_CALLBACK(mediaPlayerPrivateAudioChangedCallback), this);
+    g_signal_connect_swapped(m_pipeline.get(), "notify::source", G_CALLBACK(sourceChangedCallback), this);
+    g_signal_connect_swapped(m_pipeline.get(), "video-changed", G_CALLBACK(videoChangedCallback), this);
+    g_signal_connect_swapped(m_pipeline.get(), "audio-changed", G_CALLBACK(audioChangedCallback), this);
 #if ENABLE(VIDEO_TRACK)
     if (webkitGstCheckVersion(1, 1, 2)) {
 #if ENABLE(VIDEO_TRACK)
     if (webkitGstCheckVersion(1, 1, 2)) {
-        g_signal_connect(m_pipeline.get(), "text-changed", G_CALLBACK(mediaPlayerPrivateTextChangedCallback), this);
+        g_signal_connect_swapped(m_pipeline.get(), "text-changed", G_CALLBACK(textChangedCallback), this);
 
         GstElement* textCombiner = webkitTextCombinerNew();
         ASSERT(textCombiner);
 
         GstElement* textCombiner = webkitTextCombinerNew();
         ASSERT(textCombiner);
@@ -1978,7 +1943,7 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin()
         ASSERT(m_textAppSinkPad);
 
         g_object_set(m_textAppSink.get(), "emit-signals", true, "enable-last-sample", false, "caps", gst_caps_new_empty_simple("text/vtt"), NULL);
         ASSERT(m_textAppSinkPad);
 
         g_object_set(m_textAppSink.get(), "emit-signals", true, "enable-last-sample", false, "caps", gst_caps_new_empty_simple("text/vtt"), NULL);
-        g_signal_connect(m_textAppSink.get(), "new-sample", G_CALLBACK(mediaPlayerPrivateNewTextSampleCallback), this);
+        g_signal_connect_swapped(m_textAppSink.get(), "new-sample", G_CALLBACK(newTextSampleCallback), this);
 
         g_object_set(m_pipeline.get(), "text-sink", m_textAppSink.get(), NULL);
     }
 
         g_object_set(m_pipeline.get(), "text-sink", m_textAppSink.get(), NULL);
     }
@@ -2000,7 +1965,7 @@ void MediaPlayerPrivateGStreamer::createGSTPlayBin()
 
     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_videoSink.get(), "sink"));
     if (videoSinkPad)
 
     GRefPtr<GstPad> videoSinkPad = adoptGRef(gst_element_get_static_pad(m_videoSink.get(), "sink"));
     if (videoSinkPad)
-        g_signal_connect(videoSinkPad.get(), "notify::caps", G_CALLBACK(mediaPlayerPrivateVideoSinkCapsChangedCallback), this);
+        g_signal_connect_swapped(videoSinkPad.get(), "notify::caps", G_CALLBACK(videoSinkCapsChangedCallback), this);
 }
 
 void MediaPlayerPrivateGStreamer::simulateAudioInterruption()
 }
 
 void MediaPlayerPrivateGStreamer::simulateAudioInterruption()
index ae9abb7..f851b8a 100644 (file)
@@ -35,7 +35,6 @@
 #include <wtf/Forward.h>
 #include <wtf/RunLoop.h>
 #include <wtf/WeakPtr.h>
 #include <wtf/Forward.h>
 #include <wtf/RunLoop.h>
 #include <wtf/WeakPtr.h>
-#include <wtf/glib/GThreadSafeMainLoopSource.h>
 
 #if ENABLE(VIDEO_TRACK) && USE(GSTREAMER_MPEGTS)
 #include <wtf/text/AtomicStringHash.h>
 
 #if ENABLE(VIDEO_TRACK) && USE(GSTREAMER_MPEGTS)
 #include <wtf/text/AtomicStringHash.h>
@@ -115,26 +114,9 @@ public:
     void durationChanged();
     void loadingFailed(MediaPlayer::NetworkState);
 
     void durationChanged();
     void loadingFailed(MediaPlayer::NetworkState);
 
-    void videoChanged();
-    void videoCapsChanged();
-    void audioChanged();
-    void notifyPlayerOfVideo();
-    void notifyPlayerOfVideoCaps();
-    void notifyPlayerOfAudio();
-
-#if ENABLE(VIDEO_TRACK)
-    void textChanged();
-    void notifyPlayerOfText();
-
-    void newTextSample();
-    void notifyPlayerOfNewTextSample();
-#endif
-
     void sourceChanged();
     GstElement* audioSink() const override;
 
     void sourceChanged();
     GstElement* audioSink() const override;
 
-    void setAudioStreamProperties(GObject*);
-
     void simulateAudioInterruption() override;
 
     bool changePipelineState(GstState);
     void simulateAudioInterruption() override;
 
     bool changePipelineState(GstState);
@@ -191,6 +173,28 @@ private:
 
     void readyTimerFired();
 
 
     void readyTimerFired();
 
+    void notifyPlayerOfVideo();
+    void notifyPlayerOfVideoCaps();
+    void notifyPlayerOfAudio();
+
+#if ENABLE(VIDEO_TRACK)
+    void notifyPlayerOfText();
+    void newTextSample();
+#endif
+
+    void setAudioStreamProperties(GObject*);
+
+    static void setAudioStreamPropertiesCallback(MediaPlayerPrivateGStreamer*, GObject*);
+
+    static void sourceChangedCallback(MediaPlayerPrivateGStreamer*);
+    static void videoChangedCallback(MediaPlayerPrivateGStreamer*);
+    static void videoSinkCapsChangedCallback(MediaPlayerPrivateGStreamer*);
+    static void audioChangedCallback(MediaPlayerPrivateGStreamer*);
+#if ENABLE(VIDEO_TRACK)
+    static void textChangedCallback(MediaPlayerPrivateGStreamer*);
+    static GstFlowReturn newTextSampleCallback(MediaPlayerPrivateGStreamer*);
+#endif
+
     WeakPtrFactory<MediaPlayerPrivateGStreamer> m_weakPtrFactory;
 
     GRefPtr<GstElement> m_source;
     WeakPtrFactory<MediaPlayerPrivateGStreamer> m_weakPtrFactory;
 
     GRefPtr<GstElement> m_source;
@@ -228,10 +232,6 @@ private:
     bool m_volumeAndMuteInitialized;
     bool m_hasVideo;
     bool m_hasAudio;
     bool m_volumeAndMuteInitialized;
     bool m_hasVideo;
     bool m_hasAudio;
-    GThreadSafeMainLoopSource m_audioTimerHandler;
-    GThreadSafeMainLoopSource m_textTimerHandler;
-    GThreadSafeMainLoopSource m_videoTimerHandler;
-    GThreadSafeMainLoopSource m_videoCapsTimerHandler;
     RunLoop::Timer<MediaPlayerPrivateGStreamer> m_readyTimerHandler;
     mutable unsigned long long m_totalBytes;
     URL m_url;
     RunLoop::Timer<MediaPlayerPrivateGStreamer> m_readyTimerHandler;
     mutable unsigned long long m_totalBytes;
     URL m_url;
index 0e055e4..6ced611 100644 (file)
@@ -102,40 +102,11 @@ static int greatestCommonDivisor(int a, int b)
     return ABS(a);
 }
 
     return ABS(a);
 }
 
-static void mediaPlayerPrivateVolumeChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamerBase* player)
-{
-    // This is called when m_volumeElement receives the notify::volume signal.
-    LOG_MEDIA_MESSAGE("Volume changed to: %f", player->volume());
-    player->volumeChanged();
-}
-
-static void mediaPlayerPrivateMuteChangedCallback(GObject*, GParamSpec*, MediaPlayerPrivateGStreamerBase* player)
-{
-    // This is called when m_volumeElement receives the notify::mute signal.
-    player->muteChanged();
-}
-
-static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstSample* sample, MediaPlayerPrivateGStreamerBase* playerPrivate)
-{
-    playerPrivate->triggerRepaint(sample);
-}
-
-#if USE(GSTREAMER_GL)
-static gboolean mediaPlayerPrivateDrawCallback(GstElement*, GstContext*, GstSample* sample, MediaPlayerPrivateGStreamerBase* playerPrivate)
-{
-    playerPrivate->triggerRepaint(sample);
-    return TRUE;
-}
-#endif
-
 MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase(MediaPlayer* player)
     : m_player(player)
     , m_fpsSink(0)
     , m_readyState(MediaPlayer::HaveNothing)
     , m_networkState(MediaPlayer::Empty)
 MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase(MediaPlayer* player)
     : m_player(player)
     , m_fpsSink(0)
     , m_readyState(MediaPlayer::HaveNothing)
     , m_networkState(MediaPlayer::Empty)
-    , m_repaintHandler(0)
-    , m_volumeSignalHandler(0)
-    , m_muteSignalHandler(0)
     , m_usingFallbackVideoSink(false)
 {
     g_mutex_init(&m_sampleMutex);
     , m_usingFallbackVideoSink(false)
 {
     g_mutex_init(&m_sampleMutex);
@@ -147,24 +118,15 @@ MediaPlayerPrivateGStreamerBase::MediaPlayerPrivateGStreamerBase(MediaPlayer* pl
 
 MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
 {
 
 MediaPlayerPrivateGStreamerBase::~MediaPlayerPrivateGStreamerBase()
 {
-    if (m_repaintHandler) {
-        g_signal_handler_disconnect(m_videoSink.get(), m_repaintHandler);
-        m_repaintHandler = 0;
-    }
+    m_notifier.cancelPendingNotifications();
+
+    g_signal_handlers_disconnect_matched(m_videoSink.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
 
     g_mutex_clear(&m_sampleMutex);
 
     m_player = 0;
 
 
     g_mutex_clear(&m_sampleMutex);
 
     m_player = 0;
 
-    if (m_volumeSignalHandler) {
-        g_signal_handler_disconnect(m_volumeElement.get(), m_volumeSignalHandler);
-        m_volumeSignalHandler = 0;
-    }
-
-    if (m_muteSignalHandler) {
-        g_signal_handler_disconnect(m_volumeElement.get(), m_muteSignalHandler);
-        m_muteSignalHandler = 0;
-    }
+    g_signal_handlers_disconnect_matched(m_volumeElement.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
 
 #if USE(GSTREAMER_GL)
     g_cond_clear(&m_drawCondition);
 
 #if USE(GSTREAMER_GL)
     g_cond_clear(&m_drawCondition);
@@ -353,10 +315,12 @@ void MediaPlayerPrivateGStreamerBase::notifyPlayerOfVolumeChange()
     m_player->volumeChanged(static_cast<float>(volume));
 }
 
     m_player->volumeChanged(static_cast<float>(volume));
 }
 
-void MediaPlayerPrivateGStreamerBase::volumeChanged()
+void MediaPlayerPrivateGStreamerBase::volumeChangedCallback(MediaPlayerPrivateGStreamerBase* player)
 {
 {
-    m_volumeTimerHandler.schedule("[WebKit] MediaPlayerPrivateGStreamerBase::volumeChanged",
-        std::function<void()>([this] { notifyPlayerOfVolumeChange(); }));
+    // This is called when m_volumeElement receives the notify::volume signal.
+    LOG_MEDIA_MESSAGE("Volume changed to: %f", player->volume());
+
+    player->m_notifier.notify(MainThreadNotification::VolumeChanged, [player] { player->notifyPlayerOfVolumeChange(); });
 }
 
 MediaPlayer::NetworkState MediaPlayerPrivateGStreamerBase::networkState() const
 }
 
 MediaPlayer::NetworkState MediaPlayerPrivateGStreamerBase::networkState() const
@@ -402,10 +366,10 @@ void MediaPlayerPrivateGStreamerBase::notifyPlayerOfMute()
     m_player->muteChanged(static_cast<bool>(muted));
 }
 
     m_player->muteChanged(static_cast<bool>(muted));
 }
 
-void MediaPlayerPrivateGStreamerBase::muteChanged()
+void MediaPlayerPrivateGStreamerBase::muteChangedCallback(MediaPlayerPrivateGStreamerBase* player)
 {
 {
-    m_muteTimerHandler.schedule("[WebKit] MediaPlayerPrivateGStreamerBase::muteChanged",
-        std::function<void()>([this] { notifyPlayerOfMute(); }));
+    // This is called when m_volumeElement receives the notify::mute signal.
+    player->m_notifier.notify(MainThreadNotification::MuteChanged, [player] { player->notifyPlayerOfMute(); });
 }
 
 #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS)
 }
 
 #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS)
@@ -493,6 +457,19 @@ void MediaPlayerPrivateGStreamerBase::triggerRepaint(GstSample* sample)
     m_player->repaint();
 }
 
     m_player->repaint();
 }
 
+void MediaPlayerPrivateGStreamerBase::repaintCallback(MediaPlayerPrivateGStreamerBase* player, GstSample* sample)
+{
+    player->triggerRepaint(sample);
+}
+
+#if USE(GSTREAMER_GL)
+gboolean MediaPlayerPrivateGStreamerBase::drawCallback(MediaPlayerPrivateGStreamerBase* player, GstContext*, GstSample* sample)
+{
+    player->triggerRepaint(sample);
+    return TRUE;
+}
+#endif
+
 void MediaPlayerPrivateGStreamerBase::setSize(const IntSize& size)
 {
     m_size = size;
 void MediaPlayerPrivateGStreamerBase::setSize(const IntSize& size)
 {
     m_size = size;
@@ -592,7 +569,7 @@ GstElement* MediaPlayerPrivateGStreamerBase::createVideoSink()
     if (webkitGstCheckVersion(1, 5, 0)) {
         m_videoSink = gst_element_factory_make("glimagesink", nullptr);
         if (m_videoSink) {
     if (webkitGstCheckVersion(1, 5, 0)) {
         m_videoSink = gst_element_factory_make("glimagesink", nullptr);
         if (m_videoSink) {
-            m_repaintHandler = g_signal_connect(m_videoSink.get(), "client-draw", G_CALLBACK(mediaPlayerPrivateDrawCallback), this);
+            g_signal_connect_swapped(m_videoSink.get(), "client-draw", G_CALLBACK(drawCallback), this);
             videoSink = m_videoSink.get();
         }
     }
             videoSink = m_videoSink.get();
         }
     }
@@ -601,7 +578,7 @@ GstElement* MediaPlayerPrivateGStreamerBase::createVideoSink()
     if (!m_videoSink) {
         m_usingFallbackVideoSink = true;
         m_videoSink = webkitVideoSinkNew();
     if (!m_videoSink) {
         m_usingFallbackVideoSink = true;
         m_videoSink = webkitVideoSinkNew();
-        m_repaintHandler = g_signal_connect(m_videoSink.get(), "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
+        g_signal_connect_swapped(m_videoSink.get(), "repaint-requested", G_CALLBACK(repaintCallback), this);
     }
 
     m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
     }
 
     m_fpsSink = gst_element_factory_make("fpsdisplaysink", "sink");
@@ -647,8 +624,8 @@ void MediaPlayerPrivateGStreamerBase::setStreamVolumeElement(GstStreamVolume* vo
     LOG_MEDIA_MESSAGE("Setting stream muted %d",  m_player->muted());
     g_object_set(m_volumeElement.get(), "mute", m_player->muted(), NULL);
 
     LOG_MEDIA_MESSAGE("Setting stream muted %d",  m_player->muted());
     g_object_set(m_volumeElement.get(), "mute", m_player->muted(), NULL);
 
-    m_volumeSignalHandler = g_signal_connect(m_volumeElement.get(), "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
-    m_muteSignalHandler = g_signal_connect(m_volumeElement.get(), "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
+    g_signal_connect_swapped(m_volumeElement.get(), "notify::volume", G_CALLBACK(volumeChangedCallback), this);
+    g_signal_connect_swapped(m_volumeElement.get(), "notify::mute", G_CALLBACK(muteChangedCallback), this);
 }
 
 unsigned MediaPlayerPrivateGStreamerBase::decodedFrameCount() const
 }
 
 unsigned MediaPlayerPrivateGStreamerBase::decodedFrameCount() const
index 6d6d78b..a0c92d5 100644 (file)
 #if ENABLE(VIDEO) && USE(GSTREAMER)
 
 #include "GRefPtrGStreamer.h"
 #if ENABLE(VIDEO) && USE(GSTREAMER)
 
 #include "GRefPtrGStreamer.h"
+#include "MainThreadNotifier.h"
 #include "MediaPlayerPrivate.h"
 #include "MediaPlayerPrivate.h"
-
 #include <glib.h>
 #include <glib.h>
-
 #include <wtf/Forward.h>
 #include <wtf/glib/GThreadSafeMainLoopSource.h>
 
 #include <wtf/Forward.h>
 #include <wtf/glib/GThreadSafeMainLoopSource.h>
 
@@ -60,8 +59,6 @@ public:
 
     void setVolume(float);
     float volume() const;
 
     void setVolume(float);
     float volume() const;
-    void volumeChanged();
-    void notifyPlayerOfVolumeChange();
 
 #if USE(GSTREAMER_GL)
     bool ensureGstGLContext();
 
 #if USE(GSTREAMER_GL)
     bool ensureGstGLContext();
@@ -70,8 +67,6 @@ public:
     bool supportsMuting() const { return true; }
     void setMuted(bool);
     bool muted() const;
     bool supportsMuting() const { return true; }
     void setMuted(bool);
     bool muted() const;
-    void muteChanged();
-    void notifyPlayerOfMute();
 
     MediaPlayer::NetworkState networkState() const;
     MediaPlayer::ReadyState readyState() const;
 
     MediaPlayer::NetworkState networkState() const;
     MediaPlayer::ReadyState readyState() const;
@@ -80,7 +75,6 @@ public:
     void setSize(const IntSize&);
     void sizeChanged();
 
     void setSize(const IntSize&);
     void sizeChanged();
 
-    void triggerRepaint(GstSample*);
     void paint(GraphicsContext&, const FloatRect&);
 
     virtual bool hasSingleSecurityOrigin() const { return true; }
     void paint(GraphicsContext&, const FloatRect&);
 
     virtual bool hasSingleSecurityOrigin() const { return true; }
@@ -122,6 +116,31 @@ protected:
 
     virtual bool handleSyncMessage(GstMessage*);
 
 
     virtual bool handleSyncMessage(GstMessage*);
 
+    void triggerRepaint(GstSample*);
+
+    static void repaintCallback(MediaPlayerPrivateGStreamerBase*, GstSample*);
+#if USE(GSTREAMER_GL)
+    static gboolean drawCallback(MediaPlayerPrivateGStreamerBase*, GstContext*, GstSample*);
+#endif
+
+    void notifyPlayerOfVolumeChange();
+    void notifyPlayerOfMute();
+
+    static void volumeChangedCallback(MediaPlayerPrivateGStreamerBase*);
+    static void muteChangedCallback(MediaPlayerPrivateGStreamerBase*);
+
+    enum MainThreadNotification {
+        VideoChanged = 1 << 0,
+        VideoCapsChanged = 1 << 1,
+        AudioChanged = 1 << 2,
+        VolumeChanged = 1 << 3,
+        MuteChanged = 1 << 4,
+#if ENABLE(VIDEO_TRACK)
+        TextChanged = 1 << 5,
+#endif
+    };
+
+    MainThreadNotifier<MainThreadNotification> m_notifier;
     MediaPlayer* m_player;
     GRefPtr<GstElement> m_pipeline;
     GRefPtr<GstStreamVolume> m_volumeElement;
     MediaPlayer* m_player;
     GRefPtr<GstElement> m_pipeline;
     GRefPtr<GstStreamVolume> m_volumeElement;
@@ -132,16 +151,11 @@ protected:
     IntSize m_size;
     mutable GMutex m_sampleMutex;
     GRefPtr<GstSample> m_sample;
     IntSize m_size;
     mutable GMutex m_sampleMutex;
     GRefPtr<GstSample> m_sample;
-    GThreadSafeMainLoopSource m_volumeTimerHandler;
-    GThreadSafeMainLoopSource m_muteTimerHandler;
 #if USE(GSTREAMER_GL)
     GThreadSafeMainLoopSource m_drawTimerHandler;
     GCond m_drawCondition;
     GMutex m_drawMutex;
 #endif
 #if USE(GSTREAMER_GL)
     GThreadSafeMainLoopSource m_drawTimerHandler;
     GCond m_drawCondition;
     GMutex m_drawMutex;
 #endif
-    unsigned long m_repaintHandler;
-    unsigned long m_volumeSignalHandler;
-    unsigned long m_muteSignalHandler;
     mutable FloatSize m_videoSize;
     bool m_usingFallbackVideoSink;
 #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS)
     mutable FloatSize m_videoSize;
     bool m_usingFallbackVideoSink;
 #if USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS)