[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    kdereview/phonon/gstreamer
From:       Jens Bache-Wiig <jbache () trolltech ! com>
Date:       2008-01-17 11:19:17
Message-ID: 1200568757.850593.6788.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 762604 by jbache:

Reduced latency on gstreamer messages
We now spin a glib eventloop in the backend to
signal Qt directly about state changes rather 
than polling the bus. This should result in 
somewhat improved latency and battery consumption.



 M  +45 -23    backend.cpp  
 M  +6 -5      backend.h  
 M  +4 -0      medianode.h  
 M  +2 -1      mediaobject.cpp  
 M  +20 -4     message.cpp  
 M  +5 -1      message.h  


--- trunk/kdereview/phonon/gstreamer/backend.cpp #762603:762604
@@ -44,14 +44,15 @@
 class MediaNode;
 
 Backend::Backend(QObject *parent, const QVariantList &)
-        : QObject(parent)
-        , m_busIntervalTimer(0)
+        : QThread(parent)
         , m_deviceManager(0)
         , m_effectManager(0)
         , m_debugLevel(Warning)
         , m_isValid(false)
+        , loop(0)
 {
     gst_init (0, 0);  //init gstreamer: must be called before any gst-related \
functions +    qRegisterMetaType<Message>("Message");
 
     setProperty("identifier",     QLatin1String("phonon_gstreamer"));
     setProperty("backendName",    QLatin1String("Gstreamer"));
@@ -71,14 +72,45 @@
     m_deviceManager = new DeviceManager(this);
     m_effectManager = new EffectManager(this);
 
-    m_busIntervalTimer = new QTimer(this);
-    m_busIntervalTimer->setInterval(100);
-    connect(m_busIntervalTimer, SIGNAL(timeout()), this, SLOT(handleBusMessages()));
+    start();
 }
 
-Backend::~Backend() {}
+Backend::~Backend() 
+{
+    g_main_loop_quit (loop);
+    // Wait for thread to finish
+    QTime timeOut;
+    timeOut.start();
+    while (isRunning() && timeOut.elapsed() < 2000)
+        wait(1);
+    g_main_loop_unref (loop);
+    loop = 0;
+}
 
+gboolean Backend::busCall(GstBus *bus, GstMessage *msg, gpointer data)
+{
+    Q_UNUSED(bus);
+    Q_ASSERT(msg);
 
+    MediaObject *mediaObject = static_cast<MediaObject*>(data);
+    Q_ASSERT(mediaObject);
+
+    Message message(msg, mediaObject);
+    QMetaObject::invokeMethod(mediaObject->backend(), "handleBusMessage", \
Qt::QueuedConnection, Q_ARG(Message, message)); +
+    return true;
+}
+
+void Backend::run()
+{
+    // Default context is used by Qt so we create a new one
+    GMainContext *context = g_main_context_new();
+    loop = g_main_loop_new (context, FALSE);
+    g_main_loop_run (loop);
+    g_main_context_unref(context);
+    context = 0;
+}
+
 /***
  * !reimp
  */
@@ -331,9 +363,8 @@
  */
 void Backend::addBusWatcher(MediaObject* node)
 {
-    m_busWatchers.append(node);
-    if (m_busWatchers.size() == 1)
-        m_busIntervalTimer->start();
+    Q_ASSERT(node);
+    gst_bus_add_watch (gst_pipeline_get_bus ((GstPipeline*)node->pipeline()), \
busCall, node);  }
 
 /***
@@ -341,27 +372,18 @@
  */
 void Backend::removeBusWatcher(MediaObject* node)
 {
-    m_busWatchers.removeAll(node);
-    if (m_busWatchers.size() == 0)
-        m_busIntervalTimer->stop();
+    Q_ASSERT(node);
+    g_source_remove_by_user_data(node);
 }
 
 /***
  * Polls each mediaobject's pipeline and delivers
  * pending any pending messages
  */
-void Backend::handleBusMessages()
+void Backend::handleBusMessage(Message message)
 {
-    // iterate over all the listening media nodes and deliver the message to each \
                one
-    GstMessage* message;
-    QListIterator<MediaObject*> i(m_busWatchers);
-    while (i.hasNext()) {
-        MediaObject *mediaObject = i.next();
-        GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (mediaObject->pipeline()));
-        while ((message = gst_bus_poll(bus, GST_MESSAGE_ANY, 0)) != 0) {
-            mediaObject->handleBusMessage(Message(message));
-        }
-    }
+    MediaObject *mediaObject = message.source();
+    mediaObject->handleBusMessage(message);
 }
 
 DeviceManager* Backend::deviceManager() const
--- trunk/kdereview/phonon/gstreamer/backend.h #762603:762604
@@ -40,7 +40,8 @@
 class MediaNode;
 class MediaObject;
 class EffectManager;
-class Backend : public QObject, public BackendInterface
+
+class Backend : public QThread, public BackendInterface
 {
     Q_OBJECT
     Q_INTERFACES(Phonon::BackendInterface)
@@ -48,7 +49,6 @@
 public:
 
     enum DebugLevel {NoDebug, Warning, Info, Debug};
-
     Backend(QObject *parent = 0, const QVariantList & = QVariantList());
     virtual ~Backend();
 
@@ -57,6 +57,7 @@
 
     QObject *createObject(BackendInterface::Class, QObject *parent, const \
QList<QVariant> &args);  
+    void run();
     bool isValid() const;
     bool supportsVideo() const;
     QStringList availableMimeTypes() const;
@@ -80,17 +81,17 @@
     void objectDescriptionChanged(ObjectDescriptionType);
 
 private Q_SLOTS:
-    void handleBusMessages();
+    void handleBusMessage(Message);
 
 private:
+    static gboolean busCall(GstBus *bus, GstMessage *msg, gpointer data);
     QList<QPointer<AudioOutput> > m_audioOutputs;
-    QTimer* m_busIntervalTimer;
-    QList<MediaObject*> m_busWatchers;
 
     DeviceManager *m_deviceManager;
     EffectManager *m_effectManager;
     DebugLevel m_debugLevel;
     bool m_isValid;
+    GMainLoop *loop;
 };
 }
 } // namespace Phonon::Gstreamer
--- trunk/kdereview/phonon/gstreamer/medianode.h #762603:762604
@@ -75,6 +75,10 @@
 
     void notify(const MediaNodeEvent *event);
 
+    Backend *backend() {
+        return m_backend;
+    }
+
     const QString &name() {
         return m_name;
     }
--- trunk/kdereview/phonon/gstreamer/mediaobject.cpp #762603:762604
@@ -79,8 +79,8 @@
                     "\nhave libgstreamer-plugins-base installed."), \
Phonon::FatalError);  } else {
         m_root = this;
+        createPipeline();
         m_backend->addBusWatcher(this);
-        createPipeline();
         connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
     }
     connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)), 
@@ -936,6 +936,7 @@
                 QTimer::singleShot (qMax(0, transitionTime()), this, \
SLOT(beginPlay()));  } else {
                 stop(); // Current track completed
+                changeState(Phonon::StoppedState); //playback has already stopped so \
we can indicate this immediately   emit finished();
             }
             break;
--- trunk/kdereview/phonon/gstreamer/message.cpp #762603:762604
@@ -37,13 +37,24 @@
         m_message(0)
 {}
 
-Message::Message(GstMessage* message):
-        m_message(message)
-{}
+Message::Message(GstMessage* message, MediaObject *source):
+        m_message(message),
+        m_source(source)
+{
+    Q_ASSERT(m_message);
+    gst_message_ref(m_message);
+}
 
+Message::Message(const Message &other)
+{
+    m_message = other.m_message;
+    gst_message_ref(m_message);
+    m_source = other.m_source;
+}
+
 Message::~Message()
 {
-//    gst_message_unref(m_message); // should count?
+    gst_message_unref(m_message);
 }
 
 GstMessage* Message::rawMessage() const
@@ -51,6 +62,11 @@
     return m_message;
 }
 
+MediaObject *Message::source() const
+{
+    return m_source;
+}
+
 }   // ns gstreamer
 }   // ns phonon
 
--- trunk/kdereview/phonon/gstreamer/message.h #762603:762604
@@ -28,17 +28,21 @@
 namespace Gstreamer
 {
 
+class MediaObject;
 class Message
 {
 public:
     Message();
-    Message(GstMessage* message);
+    Message(GstMessage* message, MediaObject *source);
     ~Message();
 
     GstMessage* rawMessage() const;
+    MediaObject *source() const;
+    Message(const Message &other);
 
 private:
     GstMessage* m_message;
+    MediaObject *m_source;
 };
 
 }   // ns gstreamer


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic