[vlmc-devel] VLCMediaPlayer: Add an helper to wait for an event.

Hugo Beauzée-Luyssen git at videolan.org
Sun Sep 23 16:31:35 CEST 2012


vlmc | branch: master | Hugo Beauzée-Luyssen <beauze.h at gmail.com> | Sun Sep 23 00:00:29 2012 +0300| [c77512ce63b2c921025e56f82c3fbce9b04e44a1] | committer: Hugo Beauzée-Luyssen

VLCMediaPlayer: Add an helper to wait for an event.

> http://git.videolan.org/gitweb.cgi/vlmc.git/?a=commit;h=c77512ce63b2c921025e56f82c3fbce9b04e44a1
---

 src/LibVLCpp/VLCMediaPlayer.cpp |   61 +++++++++++++++++++++++++++++++++++
 src/LibVLCpp/VLCMediaPlayer.h   |   68 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 129 insertions(+)

diff --git a/src/LibVLCpp/VLCMediaPlayer.cpp b/src/LibVLCpp/VLCMediaPlayer.cpp
index 3301044..d471868 100644
--- a/src/LibVLCpp/VLCMediaPlayer.cpp
+++ b/src/LibVLCpp/VLCMediaPlayer.cpp
@@ -93,9 +93,38 @@ MediaPlayer::registerEvents()
  * Event dispatcher.
  */
 void
+MediaPlayer::checkForWaitedEvents(const libvlc_event_t *event)
+{
+    QMutexLocker lock( &m_mutex );
+
+    // Use the user provided callback to check if this event suits him.
+    // This is intented to filter out some events, such as multiple length changed
+    // with a value of 0
+    if ( m_eventsCallback != NULL && m_eventsCallback( this, event ) == false )
+        return ;
+    if ( m_eventsExpected.contains( event->type ) == true )
+    {
+        m_eventReceived = event->type;
+        m_waitCond.wakeAll();
+    }
+    else if ( m_eventsCancel.contains( event->type ) == true )
+    {
+        m_eventReceived = event->type;
+        m_waitCond.wakeAll();
+    }
+    //Otherwise this is an event we don't care about.
+}
+
+void
 MediaPlayer::callbacks( const libvlc_event_t* event, void* ptr )
 {
+    Q_ASSERT_X( event->type >= libvlc_MediaPlayerMediaChanged &&
+                event->type < libvlc_MediaListItemAdded, "event callback", "Only libvlc_MediaPlayer* events are supported" );
+
     MediaPlayer* self = reinterpret_cast<MediaPlayer*>( ptr );
+
+    self->checkForWaitedEvents( event );
+
     switch ( event->type )
     {
     case libvlc_MediaPlayerPlaying:
@@ -312,3 +341,35 @@ void MediaPlayer::setAudioOutput(const char *module)
 {
     libvlc_audio_output_set( m_internalPtr, module );
 }
+
+void
+MediaPlayer::configureWaitForEvent( const QList<int> &toWait, const QList<int> &cancel,
+                                    CheckEventCallback callback )
+{
+    //This mutex will only be unlocked when entering the wait condition, and upon
+    //wait completion.
+    m_mutex.lock();
+    Q_ASSERT_X( m_eventsExpected.size() == 0 && m_eventsCancel.size() == 0,
+               "waitForEvent", "waitForEvent is not supposed to be used simultaneously" );
+    m_eventsExpected.append( toWait );
+    m_eventsCancel.append( cancel );
+    m_eventReceived = 0;
+    m_eventsCallback = callback;
+}
+
+MediaPlayer::EventWaitResult
+MediaPlayer::waitForEvent( unsigned long timeoutDuration )
+{
+    bool timeout = !m_waitCond.wait( &m_mutex, timeoutDuration );
+    //m_mutex is now locked.
+    bool found = ( timeout == false && m_eventsExpected.contains( m_eventReceived ) == true );
+    m_eventsCancel.clear();
+    m_eventsExpected.clear();
+    m_eventsCallback = NULL;
+    m_eventReceived = 0;
+    m_mutex.unlock();
+    //And give feedback:
+    if ( timeout == true )
+        return Timeout;
+    return ( found ? Success : Canceled );
+}
diff --git a/src/LibVLCpp/VLCMediaPlayer.h b/src/LibVLCpp/VLCMediaPlayer.h
index fa48921..13d111f 100644
--- a/src/LibVLCpp/VLCMediaPlayer.h
+++ b/src/LibVLCpp/VLCMediaPlayer.h
@@ -23,8 +23,11 @@
 #ifndef VLCMEDIAPLAYER_H
 #define VLCMEDIAPLAYER_H
 
+#include <QList>
 #include <QMutex>
 #include <QObject>
+#include <QWaitCondition>
+
 #include "VLCpp.hpp"
 
 struct  libvlc_media_player_t;
@@ -38,6 +41,14 @@ namespace   LibVLCpp
     {
         Q_OBJECT
     public:
+        enum    EventWaitResult
+        {
+            Success, ///The event has been emited.
+            Canceled,///A cancelation event has been emited first.
+            Timeout  ///Timeout has been reached.
+        };
+        typedef bool (*CheckEventCallback)(const MediaPlayer*, const libvlc_event_t*);
+
         MediaPlayer();
         MediaPlayer( Media* media );
         ~MediaPlayer();
@@ -70,13 +81,70 @@ namespace   LibVLCpp
         void                                setKeyInput( bool enabled );
         void                                setAudioOutput(const char* module);
 
+        /**
+         * @brief configure the usage of waitForEvent.
+         *
+         * This method MUST be called before play(). It will lock a mutex
+         * that only will be unlocked in the waitForEvent() method. This mutex prevent
+         * any event processing.
+         * Using this method in any other scheme than:
+         * \li mediaPlayer->configureWaitForEvent(...);
+         * \li mediaPlayer->play();
+         * \li mediaPlayer->waitForEvents(...);
+         *
+         * is likely to result in a deadlock.
+         *
+         * @param toWait The list of events to wait for.
+         * @param cancel A list of events that would cancel the waiting process.
+         * @param callback A callback that will be called to check if this event is
+         *                  ok (for instance, accoding to the value of a changed variable)
+         *                  Callback will be called from an external thread.
+         */
+        void                                configureWaitForEvent(const QList<int> &toWait,
+                                                                    const QList<int> &cancel,
+                                                                    CheckEventCallback callback = NULL );
+        /**
+         * @brief This method will wait for one of the events specified by the
+         * list given to configureWaitForEvent().
+         *
+         * In case the waiting process should be canceled by
+         * some specific events, they shall be passed in the cancel vector.
+         * A timeout parameter can be passed. Default is to wait forever.
+         *
+         * This method MUST be called IMMEDIATLY AFTER play(), as a mutex is held,
+         * and would block any event processing until the actual waiting started.
+         *
+         * This method is concieved to wait on one unique given set of events.
+         * You can't wait for another set of events from another thread at the same time.
+         *
+         * Events (regardless of their presence in the wait or cancel list) will
+         * still be propagated to every potential receiver.
+         *
+         * @param timeout The maximum amount of time (in ms) to wait for events.
+         *
+         * @warning This method WILL BLOCK and therefore should NEVER been called
+         *          from either a VLC thread, or Qt's main thread.
+         *
+         * @returns A value as defined in the EventWaitResult enum.
+         */
+        MediaPlayer::EventWaitResult        waitForEvent( unsigned long timeout = ULONG_MAX );
+
     private:
         static void                         callbacks( const libvlc_event_t* event, void* self );
         void                                registerEvents();
+        void                                checkForWaitedEvents( const libvlc_event_t* event );
 
+    private:
         libvlc_event_manager_t*             p_em;
         Media*                              m_media;
 
+        QWaitCondition                      m_waitCond;
+        QMutex                              m_mutex;
+        int                                 m_eventReceived;
+        CheckEventCallback                  m_eventsCallback;
+        QList<int>                          m_eventsExpected;
+        QList<int>                          m_eventsCancel;
+
     signals:
         void                                snapshotTaken( const char* );
         void                                timeChanged( qint64 );



More information about the Vlmc-devel mailing list