From kde-commits Thu Jan 17 11:19:17 2008 From: Jens Bache-Wiig Date: Thu, 17 Jan 2008 11:19:17 +0000 To: kde-commits Subject: kdereview/phonon/gstreamer Message-Id: <1200568757.850593.6788.nullmailer () svn ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=120056876930510 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"); 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(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 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 &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 > m_audioOutputs; - QTimer* m_busIntervalTimer; - QList 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