From 054c652571cffb32429df2767f337dc5cd31dc30 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 15 Jan 2009 15:16:45 +0100 Subject: [PATCH 01/18] improve error handling when starting the GUI thread --- src/common/guifacade.cpp | 8 ++++---- src/gui/guifacade.hpp | 7 +++++-- src/gui/guistart.cpp | 23 ++++++++++++++++++----- src/lib/exception.cpp | 2 +- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 408c7b1d0..4adb83d47 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -60,18 +60,18 @@ namespace gui { : theGUI_("lumieraorg_Gui", 1, 1, "lumieraorg_GuiStarterPlugin") // load GuiStarterPlugin { ASSERT (theGUI_); - this->kickOff (terminationHandle); + bool res = this->kickOff (terminationHandle); - if (lumiera_error_peek()) + if (!res || lumiera_error_peek()) throw lumiera::error::Fatal("failed to bring up GUI",lumiera_error()); } ~GuiRunner () { } - void kickOff (Subsys::SigTerm& terminationHandle) + bool kickOff (Subsys::SigTerm& terminationHandle) { - theGUI_->kickOff (reinterpret_cast (&terminationHandle)); + return theGUI_->kickOff (reinterpret_cast (&terminationHandle)); } }; diff --git a/src/gui/guifacade.hpp b/src/gui/guifacade.hpp index 5afa230f0..212a62b47 100644 --- a/src/gui/guifacade.hpp +++ b/src/gui/guifacade.hpp @@ -44,6 +44,8 @@ extern "C" { #include "common/interface.h" } +#include + namespace gui { @@ -69,6 +71,7 @@ namespace gui { * */ class GuiFacade + : boost::noncopyable { public: @@ -91,7 +94,7 @@ namespace gui { * @internal this function is invoked automatically during the GUI * loading and startup process. Don't call it manually. */ - virtual void kickOff (lumiera::Subsys::SigTerm&) =0; + virtual bool kickOff (lumiera::Subsys::SigTerm&) =0; protected: @@ -100,7 +103,7 @@ namespace gui { /** interface of the GuiStarterPlugin */ LUMIERA_INTERFACE_DECLARE (lumieraorg_Gui, 1, - LUMIERA_INTERFACE_SLOT (void, kickOff, (void*)) + LUMIERA_INTERFACE_SLOT (bool, kickOff, (void*)) ); diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index e0e3b2930..08311797c 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -70,6 +70,7 @@ using std::string; using lib::Thread; using std::tr1::bind; using lumiera::Subsys; +using lumiera::error::LUMIERA_ERROR_STATE; using gui::LUMIERA_INTERFACE_INAME(lumieraorg_Gui, 1); @@ -77,7 +78,7 @@ namespace gui { namespace { // implementation details - /** + /****************************************************************************** * Implement the necessary steps for actually making the Lumiera Gui available. * Open the business interface(s) and start up the GTK GUI main event loop. */ @@ -133,10 +134,22 @@ namespace gui { } // (End) impl details - void + + + bool kickOff (Subsys::SigTerm& terminationHandle) { - Thread ("GUI-Main", bind (&runGUI, terminationHandle)); + try + { + Thread ("GUI-Main", bind (&runGUI, terminationHandle)); + return true; // if we reach this line... + } + catch(...) + { + if (!lumiera_error_peek()) + LUMIERA_ERROR_SET (gui, STATE, "unexpected error when starting the GUI thread"); + return false; + } } } // namespace gui @@ -226,9 +239,9 @@ extern "C" { /* ================== define an lumieraorg_Gui instance =========== , NULL /* on open */ , NULL /* on close */ , LUMIERA_INTERFACE_INLINE (kickOff, "\255\142\006\244\057\170\152\312\301\372\220\323\230\026\200\065", - void, (void* termSig), + bool, (void* termSig), { - gui::kickOff (*reinterpret_cast (termSig)); + return gui::kickOff (*reinterpret_cast (termSig)); } ) ) diff --git a/src/lib/exception.cpp b/src/lib/exception.cpp index d59928025..091319110 100644 --- a/src/lib/exception.cpp +++ b/src/lib/exception.cpp @@ -79,7 +79,7 @@ namespace lumiera { desc_ (description), cause_ ("") { - lumiera_error_set (this->id_, description.c_str ()); + lumiera_error_set (this->id_, description.c_str ()); } From d1d8d164e17fdcc2a51851178db47a3e1bfe1d9e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 16 Jan 2009 23:32:45 +0100 Subject: [PATCH 02/18] fix the logging flag "sync" using the wrong parent --- src/include/nobugcfg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/include/nobugcfg.h b/src/include/nobugcfg.h index 37b336503..a8d3d7d5a 100644 --- a/src/include/nobugcfg.h +++ b/src/include/nobugcfg.h @@ -83,15 +83,19 @@ namespace lumiera { /* declare flags used throughout the code base */ NOBUG_DECLARE_FLAG (all); NOBUG_DECLARE_FLAG (lumiera_all); + NOBUG_DECLARE_FLAG (lib_all); NOBUG_DECLARE_FLAG (lumiera); ///< master log, informative console output NOBUG_DECLARE_FLAG (operate); ///< logging channel reporting what the application does NOBUG_DECLARE_FLAG (render); ///< logging channel focusing on the render engine's workings NOBUG_DECLARE_FLAG (config); ///< logging channel covering application and session configuration NOBUG_DECLARE_FLAG (memory); ///< logging channel covering memory management issues - NOBUG_DECLARE_FLAG (sync); ///< especially for tracing synchronisation NOBUG_DECLARE_FLAG (test); + /* further flags which don't fit into any specific translation unit */ + NOBUG_DECLARE_FLAG (sync); ///< especially for tracing synchronisation + + #endif /*NOBUGCFG_H ======= (End) Part 1: DECLARATIONS ======== */ @@ -105,15 +109,18 @@ namespace lumiera { /* flags used throughout the code base... */ NOBUG_CPP_DEFINE_FLAG (all); NOBUG_CPP_DEFINE_FLAG_PARENT (lumiera_all, all); + NOBUG_CPP_DEFINE_FLAG_PARENT (lib_all, all); + NOBUG_CPP_DEFINE_FLAG_PARENT (lumiera, lumiera_all); NOBUG_CPP_DEFINE_FLAG_PARENT (config, lumiera); NOBUG_CPP_DEFINE_FLAG_PARENT (operate, lumiera); NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (render, lumiera, LOG_WARNING); NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (memory, lumiera, LOG_WARNING); - NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (sync, memory, LOG_WARNING); NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (test, all, LOG_ERR); + NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT (sync, lib_all, LOG_WARNING); + #endif /*NOBUG_INIT_DEFS_ ==== (End) Part 2: DEFINITIONS ========= */ From ff78f9e535469b3d712d5bf180d14827c9261d7b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Jan 2009 14:58:48 +0100 Subject: [PATCH 03/18] concept sketch --- doc/devel/draw/PlayerArch-1.svg | 412 ++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 doc/devel/draw/PlayerArch-1.svg diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg new file mode 100644 index 000000000..8e7b3f9b8 --- /dev/null +++ b/doc/devel/draw/PlayerArch-1.svg @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + AllocationCluster + + + Ichthyostega + + + design sketch: Structure of the AllocationCluster mem manager + 2008 + + + + + + + + + + + + + + + + + Displayer + OutSink + put(Frame&) + Display(facade) + + + + createProcess(...) + OutputProcess + Player(facade) + openDisplayer(...) + + + uses + GUI (Plugin) + Backend (or Proc?) + + Displayer (Proxy) + DisplayFacade (Proxy) + + C Language Interface of the GUI-Plugin + + + actuallytalks to... + + libCommon + From 2679156a9c04a2ced27206cfa3245038f3b7e198 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Jan 2009 15:18:58 +0100 Subject: [PATCH 04/18] Thread-wrapper: improve comments, push action down into private function --- src/backend/thread-wrapper.hpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 3c60cda09..2280d097c 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -42,8 +42,10 @@ namespace lib { using std::tr1::function; using lumiera::Literal; + typedef struct nobug_flag* NoBugFlag; - /** + + /**************************************************************************** * A thin convenience wrapper for dealing with threads, * as implemented by the backend (on top of pthread). * Using this wrapper... @@ -87,10 +89,8 @@ namespace lib { } - public: - Thread (Literal& purpose, Operation const& operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) - : started_(false), - operation_(operation) + void + start_thread (Literal& purpose, NoBugFlag logging_flag) { Lock sync(this); LumieraThread res = @@ -109,6 +109,26 @@ namespace lib { // prior to leaving and thereby possibly destroying this local context sync.wait (started_); } + + public: + /** Create a new thread to execute the given operation. + * The new thread starts up synchronously, i.e. when the ctor returns, the new thread + * has started running and taken over (copied) the operation functor passed in. The + * thread will be created by lumiera_thread_run (declared in threads.h), it can't + * be cancelled and it can't be joined. + * @param purpose fixed char string used to denote the thread for diagnostics + * @param logging_flag NoBug flag to receive diagnostics regarding the new thread + * @param operation defining what to execute within the new thread. Any functor + * which can be bound to function. Note this functor will be + * copied onto the stack of the new thread, thus it can be transient. + * + */ + Thread (Literal& purpose, Operation const& operation, NoBugFlag logging_flag = &NOBUG_FLAG(operate)) ///TODO: define a dedicated flag for threads + : started_(false), + operation_(operation) + { + start_thread (purpose, logging_flag); + } }; From c6bc14375cf4e1ce3133d26a8e3a5ebd8cf024a9 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Jan 2009 16:14:00 +0100 Subject: [PATCH 05/18] write a draft how I'd like to deal with joining threads. --- src/backend/thread-wrapper.hpp | 105 +++++++++++++++++++++++++++++++-- src/lib/sync.hpp | 7 +++ 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 2280d097c..d4dfc1e70 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -44,6 +44,85 @@ namespace lib { typedef struct nobug_flag* NoBugFlag; + class Thread; + + /** + * Brainstorming-in-code: how I would like to shape the API for joining threads. + * Intended use: This non-copyable handle has to be created within the thread which + * wants to wait-blocking on the termination of another thread. You then pass it + * into the ctor of the Thread starting wrapper class (see below), which causes + * the embedded lock/condition var to be used to sync on the end of the newly + * created thread. Note, after ending the execution, the newly created thread + * will be on hold until either the #join() function is called or this handle + * goes out of scope altogether. Explanation: this is implemented by locking + * the embedded monitor immediately in the ctor. Thus, unless entering the + * wait state, the contained mutex remains locked and prevents the thread + * manager from invoking the broadcast() on the condition var. + * + * @note this is a draft. It doesn't even work, because Cehteh is still planning + * details of the thread handling and didn't implement the waiting feature. + */ + class JoinHandle + : public Sync + , Sync::Lock + { + typedef Sync SyncBase; + + bool isWaiting_; + volatile bool armed_; + + friend class Thread; + + LumieraCondition + accessLockedCondition() + { + ASSERT (!armed_, "Lifecycle error, JoinHandle used for several threads."); + armed_ = true; + return accessMonitor().accessCond(); + } + + bool + wakeupCheck() + { + if (!armed_) + throw lumiera::error::Logic ("no thread created blocking on this JoinHandle"); + + if (!isWaiting_) + { + isWaiting_ = true; + return false; // causes entering the blocking wait + } + TODO ("any possibility to detect spurious wakeups? can they happen?"); + return true; // causes end of the blocking wait + } + + + public: + /** Create a promise, that the current thread will or may + * wait-blocking on another not-yet existing thread to terminate. + * When passed in on creation of the other thread, as long as this + * handle lives, the other thread will be on hold after termination. + */ + JoinHandle() + : SyncBase::Lock(this) + , isWaiting_(false) + , armed_(false) + { } + + /** put the current thread into a blocking wait until another thread + * has terminated. This other thread needs to be created by the Thread + * wrapper, passing this JoinHandle as ctor parameter. + * @throws error::Logic if no thread has been registered to block on this + */ + void + join() + { + accessMonitor().wait (*this, &JoinHandle::wakeupCheck); + } + }; + + + /**************************************************************************** * A thin convenience wrapper for dealing with threads, @@ -65,8 +144,8 @@ namespace lib { * is superfluous in the final application. Re-evaluate this! */ class Thread - : public Sync, - boost::noncopyable + : public Sync + , boost::noncopyable { volatile bool started_; @@ -90,14 +169,14 @@ namespace lib { void - start_thread (Literal& purpose, NoBugFlag logging_flag) + start_thread (lumiera_thread_class kind, Literal& purpose, NoBugFlag logging_flag, LumieraCondition joinCond=0) { Lock sync(this); LumieraThread res = - lumiera_thread_run ( LUMIERA_THREAD_INTERACTIVE + lumiera_thread_run ( kind , &run // invoking the run helper and.. , this // passing this start context as parameter - , 0 // no condition variable provided (for now...) + , joinCond // maybe wait-blocking for the thread to terminate , purpose.c_str() , logging_flag ); @@ -127,7 +206,21 @@ namespace lib { : started_(false), operation_(operation) { - start_thread (purpose, logging_flag); + start_thread (LUMIERA_THREAD_INTERACTIVE, purpose, logging_flag); + } + + /** Variant of the standard case, used to register a JoinHandle in addition to starting a thread. + * @param join ref to a JoinHandle, which needs to be created in the thread which plans + * to wait-blocking on the termination of this newly created thread + * + */ + Thread (Literal& purpose, Operation const& operation, + JoinHandle& join, NoBugFlag logging_flag = &NOBUG_FLAG(operate)) ///TODO: define a dedicated flag for threads + : started_(false), + operation_(operation) + { + start_thread (LUMIERA_THREAD_INTERACTIVE, purpose, logging_flag, + join.accessLockedCondition()); } }; diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index ef08e7f83..4abc55993 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -331,6 +331,8 @@ namespace lib { void setTimeout(ulong relative) {timeout_.setOffset(relative);} bool isTimedWait() {return (timeout_);} + + LumieraCondition accessCond() {return static_cast (this);} }; typedef Mutex NonrecursiveLock_NoWait; @@ -419,6 +421,11 @@ namespace lib { /** for creating a ClassLock */ Lock(Monitor& m) : mon_(m) { mon_.acquireLock(); } + + /** for controlled access to the + * underlying sync primitives */ + Monitor& + accessMonitor() { return mon_; } }; From 810e531508b7534e01577b5c2da2a3a07deb547f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 18 Jan 2009 16:59:24 +0100 Subject: [PATCH 06/18] perpare a test (which of course currently fails).... --- tests/40components.tests | 4 + tests/lib/Makefile.am | 1 + tests/lib/singletonsubclasstest.cpp | 1 + tests/lib/thread-wrapper-join-test.cpp | 141 +++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 tests/lib/thread-wrapper-join-test.cpp diff --git a/tests/40components.tests b/tests/40components.tests index 6ed448349..ba14f909f 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -337,6 +337,10 @@ return: 0 END +PLANNED "Waiting on Thread termination" ThreadWrapperJoin_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" + +#include "include/symbol.hpp" +#include "backend/thread-wrapper.hpp" +#include "lib/error.hpp" +#include "lib/sync.hpp" + +#include + +using std::tr1::bind; +using test::Test; + + + +namespace lib { + namespace test { + + /************************************************************************** + * @test use the Lumiera backend to create some new threads, additionally + * passing an condition variable for waiting on thread termination. + * Actually this is implemented as creating and passing a JoinHandle. + * + * @see lib::Thread + * @see threads.h + */ + class ThreadWrapperJoin_test : public Test + { + + virtual void + run (Arg) + { + simpleUse (); + wrongUse (); + } + + + volatile int aValue_; ///< state to be modified by the other thread + + void + theAction (int secretValue) ///< to be run in a new thread... + { + sleep(1); + aValue_ = secretValue+42; + } + + + void + simpleUse () + { + aValue_=0; + int mySecret = (rand() % 1000) - 500; + + JoinHandle waitingHandle; + + Thread("test Thread joining", + bind (&ThreadWrapperJoin_test::theAction, this, mySecret), + waitingHandle); + // note binding and thread wrapper already destroyed + + waitingHandle.join(); // blocks until theAction() is done + + ASSERT (aValue_ == mySecret+42); + } + + + void + wrongUse () + { + JoinHandle waitingHandle; + + Thread("test Thread joining-1", + bind (&ThreadWrapperJoin_test::theAction, this, 111)); + // note we "forget" to pass the JoinHandle + try + { + waitingHandle.join(); // protocol error: handle wasn't passed for starting a Thread; + NOTREACHED; + } + catch (lumiera::error::Logic& logo) + { lumiera_error(); } + + + Thread("test Thread joining-2", + bind (&ThreadWrapperJoin_test::theAction, this, 222), + waitingHandle); // this time we pass it.... + +#ifdef DEBUG + /////////////////////////////////////////////////////////////////////////////////////////////TODO: better way of detecting debug builds + try + { + Thread("test Thread joining-3", + bind (&ThreadWrapperJoin_test::theAction, this, 333), + waitingHandle); // but then pass it again for another thread.... + NOTREACHED; + } + catch (...) + { + ASSERT (lumiera_error() == lumiera::error::LUMIERA_ERROR_ASSERTION); + } +#endif + + // note: the waitingHandle goes out of scope here, + // which unblocks the second thread. The first thread wasn't blocked, + // while the third thread wasn't created at all. + } + + }; + + + + /** Register this test class... */ + LAUNCHER (ThreadWrapperJoin_test, "function common"); + + + + } // namespace test + +} // namespace lib From 198d6bde7304fc0d474ef4059513a4d15407b193 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 Jan 2009 02:21:41 +0100 Subject: [PATCH 07/18] better make GuiNotification an experimental interface (Version=0) --- src/gui/notification-service.cpp | 2 +- src/gui/notification-service.hpp | 2 +- src/include/guinotificationfacade.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index f713d7390..fcbec39e8 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -139,7 +139,7 @@ namespace gui { - LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 1 + LUMIERA_INTERFACE_INSTANCE (lumieraorg_GuiNotification, 0 ,lumieraorg_GuiNotificationFacade , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_GuiNotificationFacade_descriptor) , NULL /* on open */ diff --git a/src/gui/notification-service.hpp b/src/gui/notification-service.hpp index 41e404e46..63ef677a4 100644 --- a/src/gui/notification-service.hpp +++ b/src/gui/notification-service.hpp @@ -73,7 +73,7 @@ namespace gui { /* === Interface Lifecycle === */ - typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) , GuiNotification > ServiceInstanceHandle; diff --git a/src/include/guinotificationfacade.h b/src/include/guinotificationfacade.h index 9f4f91474..f3e334bff 100644 --- a/src/include/guinotificationfacade.h +++ b/src/include/guinotificationfacade.h @@ -85,7 +85,7 @@ extern "C" { #include "common/interface.h" -LUMIERA_INTERFACE_DECLARE (lumieraorg_GuiNotification, 1, +LUMIERA_INTERFACE_DECLARE (lumieraorg_GuiNotification, 0, LUMIERA_INTERFACE_SLOT (void, displayInfo, (const char*)), LUMIERA_INTERFACE_SLOT (void, triggerGuiShutdown, (const char*)), ); From 29b9887faa9a8bc4ccdf5c4dfdb4d70d742f68ca Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 Jan 2009 11:38:20 +0100 Subject: [PATCH 08/18] first draft of a Dummy-Player service --- SConstruct | 2 +- doc/devel/draw/PlayerArch-1.svg | 276 ++++++++++++++++++------------ src/include/dummy-player-facade.h | 119 +++++++++++++ src/proc/dummy-player-service.cpp | 85 +++++++++ src/proc/dummy-player-service.hpp | 92 ++++++++++ 5 files changed, 463 insertions(+), 111 deletions(-) create mode 100644 src/include/dummy-player-facade.h create mode 100644 src/proc/dummy-player-service.cpp create mode 100644 src/proc/dummy-player-service.hpp diff --git a/SConstruct b/SConstruct index dc0f76864..7a1aa2592 100644 --- a/SConstruct +++ b/SConstruct @@ -257,7 +257,7 @@ def configurePlatform(env): if not conf.CheckPkgConfig('glibmm-2.4', '2.16'): problems.append('Unable to configure Lib glib--, exiting.') - if not conf.CheckPkgConfig('gthread-2.0', '2.12'): + if not conf.CheckPkgConfig('gthread-2.0', '2.12.4'): problems.append('Need gthread support lib for glib-- based thread handling.') if not conf.CheckPkgConfig('cairomm-1.0', 0.6): diff --git a/doc/devel/draw/PlayerArch-1.svg b/doc/devel/draw/PlayerArch-1.svg index 8e7b3f9b8..519d5317d 100644 --- a/doc/devel/draw/PlayerArch-1.svg +++ b/doc/devel/draw/PlayerArch-1.svg @@ -25,8 +25,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2" - inkscape:cx="466.20838" - inkscape:cy="425.69964" + inkscape:cx="346.20838" + inkscape:cy="304.01881" inkscape:document-units="px" inkscape:current-layer="svg2" inkscape:window-width="1668" @@ -145,18 +145,18 @@ id="rect4200" width="130.423" height="70.324265" - x="439.99997" - y="229.87326" /> + x="340" + y="260" /> + width="110.59406" + height="30.243902" + x="249.40594" + y="169.7561" /> Displayer - OutSink + x="260" + y="180" + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">play thread put(Frame&) Display(facade) + y="143.5">PlaybackController - createProcess(...) + style="font-size:8px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">start(...) OutputProcess + x="240" + y="410" + style="font-size:8px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans" + id="tspan2218">PlayProcess Player(facade) + y="263.5">Player (interface) openDisplayer(...) + sodipodi:role="line">start_playback_thread() uses + x="220" + y="290" + style="font-size:7px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-opacity:1;font-family:Bitstream Vera Sans">yields Backend (or Proc?) + y="370">Proc (or Backend?) Displayer (Proxy) DisplayFacade (Proxy) - - C Language Interface of the GUI-Plugin + x="345.00003" + y="273.12677" + style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans">PlayerFacade (Proxy) + d="M 110,290 L 210,290 L 270,390" + id="path3481" + sodipodi:nodetypes="ccc" /> actuallytalks to... - libCommon + x="480.00003" + y="280.12677">libCommon + + + PlayContext + PlayerService + + + + PlayContext + PlayContext + PlayContext + diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h new file mode 100644 index 000000000..807f48393 --- /dev/null +++ b/src/include/dummy-player-facade.h @@ -0,0 +1,119 @@ +/* + DUMMY-PLAYER-FACADE.hpp - access point to a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef PROC_INTERFACE_DUMMYPLAYER_H +#define PROC_INTERFACE_DUMMYPLAYER_H + + + +struct lumiera_playprocess_struct { }; +typedef struct lumiera_playprocess_struct lumiera_playprocess; +typedef lumiera_playprocess* LumieraPlayProcess; + + + + +#ifdef __cplusplus /* ============== C++ Interface ================= */ + +#include "common/subsys.hpp" +#include "include/interfaceproxy.hpp" + + + + +namespace proc { + + class PlayProcess; + + + /****************************************************************** + * Interface Proc-Layer (or maybe the backend?): + * Global access point for starting a dummy playback, generating + * some test image data for the GUI to display in a viewer window. + * + * This is a mockup service we created 1/2009 to collect some + * experiences regarding integration of the application layers. + * Lumiera is not yet able actually to deliver rendered video data. + * + */ + class DummyPlayer + { + public: + /** provide a descriptor for lumiera::AppState, + * wired accordingly to allow main to deal with + * the dummy player as independent subsystem. */ + static lumiera::Subsys& getDescriptor(); + + /** get an implementation instance of this service */ + static lumiera::facade::Accessor facade; + + + //////////////////TODO: define some dummy negotiation about size and framerate.... + + virtual PlayProcess& start() =0; + + virtual ~DummyPlayer(); + }; + + + /** + * Continuous playback process, which has been started with a specific + * output size, format and framerate. It is a handle to a calculation process, + * which is about to produce a stream of frames to be retrieved by calling + * the #getFrame function on this handle. + * + * @todo solve the lifecycle and ownership! + */ + class PlayProcess + : public LumieraPlayProcess + { + public: + virtual void pause(bool) =0; + virtual void* const getFrame() =0; + + virtual ~PlayProcess(); + }; + + +} // namespace proc + + + +extern "C" { +#endif /* =========================== CL Interface ===================== */ + + +#include "common/interface.h" + +LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 + , LUMIERA_INTERFACE_SLOT (LumieraPlayProcess, startPlay,(void) ) + , LUMIERA_INTERFACE_SLOT (void, pausePlay,(LumieraPlayProcess, bool)) + , LUMIERA_INTERFACE_SLOT (void, terminate,(LumieraPlayProcess) ) + , LUMIERA_INTERFACE_SLOT (void *, getFrame, (LumieraPlayProcess) ) +); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp new file mode 100644 index 000000000..a728613af --- /dev/null +++ b/src/proc/dummy-player-service.cpp @@ -0,0 +1,85 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/dummy-player-service.hpp" +#include "lib/singleton.hpp" + +#include + + +namespace proc { + + using std::string; + using lumiera::Subsys; + + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Engine"; } + + bool + shouldStart (lumiera::Option&) + { + TODO ("determine, if renderengine should be started"); + return false; + } + + bool + start (lumiera::Option&, Subsys::SigTerm termination) + { + UNIMPLEMENTED ("pull up renderengine and register shutdown hook"); + return false; + } + + void + triggerShutdown () throw() + { + UNIMPLEMENTED ("initiate halting the engine"); + } + + bool + checkRunningState () throw() + { + //Lock guard (*this); + TODO ("implement detecting running state"); + return false; + } + }; + + namespace { + lumiera::Singleton theDescriptor; + } + + + + + /** @internal intended for use by main(). */ + Subsys& + DummyPlayer::getDescriptor() + { + return theDescriptor(); + } + + + +} // namespace proc diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp new file mode 100644 index 000000000..76d06881a --- /dev/null +++ b/src/proc/dummy-player-service.hpp @@ -0,0 +1,92 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file notification-service.hpp + ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. + ** The purpose of this service is to push state update and notification of events from the lower + ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events + ** within the lower layers. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see gui::GuiFacade + ** @see guifacade.cpp starting this service + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + + + +namespace proc { + + + + /****************************************************** + * Actual implementation of the GuiNotification service + * within the Lumiera GTK GUI. Creating an instance of + * this class automatically registers the interface + * with the Lumiera Interface/Plugin system and creates + * a forwarding proxy within the application core to + * route calls through this interface. + * + * @todo the ctor of this class should take references + * to any internal service providers within the + * GUI which are needed to implement the service. + */ + class DummyPlayerService + : public DummyPlayer + { + + /* === Implementation of the Facade Interface === */ + + void displayInfo (string const& text); + void triggerGuiShutdown (string const& cause); + + + /* === Interface Lifecycle === */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , DummyPlayer + > ServiceInstanceHandle; + + lib::SingletonRef implInstance_; + ServiceInstanceHandle serviceInstance_; + + public: + DummyPlayerService(); + + }; + + + +} // namespace proc +#endif From 60d41ea0173006e21d7b6e88cb4d9ffdb1ebc689 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 Jan 2009 12:43:28 +0100 Subject: [PATCH 09/18] WIP (unfinished, doesn't compile) flesh out some impl details --- src/gui/notification-service.cpp | 2 +- src/include/dummy-player-facade.h | 47 +++--- src/proc/dummy-player-service.cpp | 246 +++++++++++++++++++++++++----- src/proc/dummy-player-service.hpp | 17 ++- 4 files changed, 252 insertions(+), 60 deletions(-) diff --git a/src/gui/notification-service.cpp b/src/gui/notification-service.cpp index fcbec39e8..eca7c268f 100644 --- a/src/gui/notification-service.cpp +++ b/src/gui/notification-service.cpp @@ -171,7 +171,7 @@ namespace gui { NotificationService::NotificationService () : implInstance_(this,_instance), - serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 1,lumieraorg_GuiNotificationFacade)) + serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_GuiNotification, 0,lumieraorg_GuiNotificationFacade)) { INFO (operate, "GuiNotification Facade opened."); } diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 807f48393..1b12a0bfa 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -38,12 +38,12 @@ typedef lumiera_playprocess* LumieraPlayProcess; #include "common/subsys.hpp" #include "include/interfaceproxy.hpp" +#include namespace proc { - - class PlayProcess; + /****************************************************************** @@ -68,31 +68,34 @@ namespace proc { static lumiera::facade::Accessor facade; + /** + * Continuous playback process, which has been started with a specific + * output size, format and framerate. It is a handle to a calculation process, + * which is about to produce a stream of frames to be retrieved by calling + * the #getFrame function on this handle. + * + * @todo solve the lifecycle and ownership! + */ + class Process + : public LumieraPlayProcess, + boost::noncopyable + { + public: + virtual void pause(bool) =0; + virtual void* const getFrame() =0; + + virtual ~Process(); + }; + + //////////////////TODO: define some dummy negotiation about size and framerate.... - virtual PlayProcess& start() =0; + virtual Process& start() =0; virtual ~DummyPlayer(); }; - /** - * Continuous playback process, which has been started with a specific - * output size, format and framerate. It is a handle to a calculation process, - * which is about to produce a stream of frames to be retrieved by calling - * the #getFrame function on this handle. - * - * @todo solve the lifecycle and ownership! - */ - class PlayProcess - : public LumieraPlayProcess - { - public: - virtual void pause(bool) =0; - virtual void* const getFrame() =0; - - virtual ~PlayProcess(); - }; } // namespace proc @@ -100,9 +103,9 @@ namespace proc { extern "C" { -#endif /* =========================== CL Interface ===================== */ +#endif /* =========================== CL Interface ===================== */ + - #include "common/interface.h" LUMIERA_INTERFACE_DECLARE (lumieraorg_DummyPlayer, 0 diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index a728613af..863462c9e 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -25,49 +25,227 @@ #include "lib/singleton.hpp" #include +#include namespace proc { using std::string; using lumiera::Subsys; + using boost::scoped_ptr; - class DummyPlayerSubsysDescriptor - : public Subsys - { - operator string () const { return "Engine"; } - - bool - shouldStart (lumiera::Option&) - { - TODO ("determine, if renderengine should be started"); - return false; - } - - bool - start (lumiera::Option&, Subsys::SigTerm termination) - { - UNIMPLEMENTED ("pull up renderengine and register shutdown hook"); - return false; - } - - void - triggerShutdown () throw() - { - UNIMPLEMENTED ("initiate halting the engine"); - } - - bool - checkRunningState () throw() - { - //Lock guard (*this); - TODO ("implement detecting running state"); - return false; - } - }; - namespace { + namespace { // hidden local details of the service implementation.... + + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr thePlayer_; + + + void + triggerShutdown () throw() + { + TODO ("implement waiting for any playback processes to terminate gracefully"); + //..... but this would require us to use a separate thread, so I skip it for now. + // Probably it's better design to mange the processes in a separate thread anyway... + + thePlayer_.reset(0); + } + + bool + checkRunningState () throw() + { + //note: not locking here... + return (thePlayer_); + } + }; + lumiera::Singleton theDescriptor; + + + + + + /* ================== define an lumieraorg_GuiNotification instance ======================= */ + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 + ,lumieraorg_DummyPlayerFacade_descriptor + , NULL, NULL, NULL + , LUMIERA_INTERFACE_INLINE (name, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "DummyPlayer"; } + ) + , LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } + ) + , LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} + ) + , LUMIERA_INTERFACE_INLINE (version, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "0.1~pre"; } + ) + , LUMIERA_INTERFACE_INLINE (author, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "Hermann Vosseler"; } + ) + , LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + const char*, (LumieraInterface ifa), + { (void)ifa; return "Ichthyostega@web.de"; } + ) + , LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN, + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "Copyright (C) Lumiera.org\n" + " 2009 Hermann Vosseler "; + } + ) + , LUMIERA_INTERFACE_INLINE (license, LUIDGEN, + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; + } + ) + , LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + int, (LumieraInterface ifa), + {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } + ) + , LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + int, (const char* a, const char* b), + {return 0;} ////////////////////////////////////////////TODO define version ordering + ) + ); + + + + + + using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; + typedef lib::SingletonRef::Accessor InstanceRef; + + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual GuiNotification implementation... + + typedef DummyPlayer::Process* ProcP; + + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 + ,lumieraorg_DummyPlayerFacade + , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) + , NULL /* on open */ + , NULL /* on close */ + , LUMIERA_INTERFACE_INLINE (startPlay, LUIDGEN, + LumieraPlayProcess, (void), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return 0; + } + + return static_cast (& (_instance->start())); + } + ) + , LUMIERA_INTERFACE_INLINE (pausePlay, LUIDGEN, + void, (LumieraPlayProcess handle, bool doPlay), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = dynamic_cast (handle); + ASSERT (proc); + + proc->pause(doPlay); + } + ) + , LUMIERA_INTERFACE_INLINE (terminate, LUIDGEN, + void, (LumieraPlayProcess handle), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = dynamic_cast (handle); + ASSERT (proc); + + UNIMPLEMENTED ("terminate a running playback process"); + } + ) + , LUMIERA_INTERFACE_INLINE (getFrame, LUIDGEN, + void *, (LumieraPlayProcess handle), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return 0; + } + + REQUIRE (handle); + ProcP proc = dynamic_cast (handle); + ASSERT (proc); + + return const_cast (proc->getFrame()); + } + ) + ); + + + + + } // (End) hidden service impl details + + + + + DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) + : notifyTermination_(terminationHandle) + , implInstance_(this,_instance) + , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) + { + INFO (operate, "GuiNotification Facade opened."); } diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp index 76d06881a..2a4aaf734 100644 --- a/src/proc/dummy-player-service.hpp +++ b/src/proc/dummy-player-service.hpp @@ -68,8 +68,17 @@ namespace proc { /* === Implementation of the Facade Interface === */ - void displayInfo (string const& text); - void triggerGuiShutdown (string const& cause); + Process& start(); + + + /** for now we use an single inline Process... + * @todo actually implement multiple independent Playback processes! + * @todo I am aware holding this object inline may cause a segfault at shutdown! + */ + Process theProcess_; + + Subsys::SigTerm notifyTermination_; + /* === Interface Lifecycle === */ @@ -82,7 +91,9 @@ namespace proc { ServiceInstanceHandle serviceInstance_; public: - DummyPlayerService(); + DummyPlayerService(Subsys::SigTerm terminationHandle); + + ~DummyPlayerService() { notifyTermination_(); } }; From 962921d375d6a688cee3008a8495ac68c3c7eb7e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 20 Jan 2009 12:41:21 +0100 Subject: [PATCH 10/18] WIP (still doesnt compile...) add impl of the forwarding proxy... --- src/common/interfaceproxy.cpp | 57 +++++++++++++++++++++++++++-- src/include/dummy-player-facade.h | 4 +-- src/proc/dummy-player-service.cpp | 60 ++++++++++++++++--------------- src/proc/dummy-player-service.hpp | 19 ++++++++-- 4 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 6cbc8b4cb..984555f28 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -40,6 +40,17 @@ namespace gui { +#include "include/dummy-player-facade.h" + +namespace proc { + + /** storage for the DummyPlayer facade proxy factory... */ + lumiera::facade::Accessor DummyPlayer::facade; + +} // namespace gui + + + namespace lumiera { namespace facade { @@ -107,7 +118,9 @@ namespace lumiera { - typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 1) + /* ==================== GuiNotification =================================== */ + + typedef InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_GuiNotification, 0) , gui::GuiNotification > Handle_GuiNotification; @@ -127,12 +140,50 @@ namespace lumiera { }; - - template void openProxy (Handle_GuiNotification const&); template void closeProxy (void); + + + + + + /* ==================== DummyPlayer ======================================= */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , proc::DummyPlayer + > Handle_DummyPlayer; + + + template<> + class Proxy + : public Holder + { + //----Proxy-Implementation-of-DummyPlayer-------- + typedef proc::DummyPlayer::Process Process; + + Process& start() + { + Process* pP = static_cast (_i_.startPlay()); + + if (!pP || lumiera_error_peek()) + throw lumiera::error::State("failed to start DummyPlayer", lumiera_error()); + + return *pP; + } + + + + public: + Proxy (IHandle const& iha) : THolder(iha) {} + }; + + + template void openProxy (Handle_DummyPlayer const&); + template void closeProxy (void); + + } // namespace facade } // namespace lumiera diff --git a/src/include/dummy-player-facade.h b/src/include/dummy-player-facade.h index 1b12a0bfa..2899096c0 100644 --- a/src/include/dummy-player-facade.h +++ b/src/include/dummy-player-facade.h @@ -77,8 +77,8 @@ namespace proc { * @todo solve the lifecycle and ownership! */ class Process - : public LumieraPlayProcess, - boost::noncopyable + : public lumiera_playprocess + , boost::noncopyable { public: virtual void pause(bool) =0; diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index 863462c9e..400bfafa4 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -24,6 +24,10 @@ #include "proc/dummy-player-service.hpp" #include "lib/singleton.hpp" +extern "C" { +#include "common/interfacedescriptor.h" +} + #include #include @@ -37,11 +41,14 @@ namespace proc { namespace { // hidden local details of the service implementation.... + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ class DummyPlayerSubsysDescriptor : public Subsys { operator string () const { return "Dummy-Player"; } + bool shouldStart (lumiera::Option&) { @@ -66,7 +73,7 @@ namespace proc { { TODO ("implement waiting for any playback processes to terminate gracefully"); //..... but this would require us to use a separate thread, so I skip it for now. - // Probably it's better design to mange the processes in a separate thread anyway... + // Probably it's better design to manage the processes in a separate thread anyway... thePlayer_.reset(0); } @@ -90,31 +97,31 @@ namespace proc { LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 ,lumieraorg_DummyPlayerFacade_descriptor , NULL, NULL, NULL - , LUMIERA_INTERFACE_INLINE (name, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307", const char*, (LumieraInterface ifa), { (void)ifa; return "DummyPlayer"; } ) - , LUMIERA_INTERFACE_INLINE (brief, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232", const char*, (LumieraInterface ifa), { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } ) - , LUMIERA_INTERFACE_INLINE (homepage, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200", const char*, (LumieraInterface ifa), { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} ) - , LUMIERA_INTERFACE_INLINE (version, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165", const char*, (LumieraInterface ifa), { (void)ifa; return "0.1~pre"; } ) - , LUMIERA_INTERFACE_INLINE (author, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105", const char*, (LumieraInterface ifa), { (void)ifa; return "Hermann Vosseler"; } ) - , LUMIERA_INTERFACE_INLINE (email, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206", const char*, (LumieraInterface ifa), { (void)ifa; return "Ichthyostega@web.de"; } ) - , LUMIERA_INTERFACE_INLINE (copyright, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210", const char*, (LumieraInterface ifa), { (void)ifa; @@ -123,7 +130,7 @@ namespace proc { " 2009 Hermann Vosseler "; } ) - , LUMIERA_INTERFACE_INLINE (license, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060", const char*, (LumieraInterface ifa), { (void)ifa; @@ -143,11 +150,11 @@ namespace proc { "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; } ) - , LUMIERA_INTERFACE_INLINE (state, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350", int, (LumieraInterface ifa), {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } ) - , LUMIERA_INTERFACE_INLINE (versioncmp, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126", int, (const char* a, const char* b), {return 0;} ////////////////////////////////////////////TODO define version ordering ) @@ -158,9 +165,9 @@ namespace proc { using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; - typedef lib::SingletonRef::Accessor InstanceRef; + typedef lib::SingletonRef::Accessor InstanceRef; - InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual GuiNotification implementation... + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... typedef DummyPlayer::Process* ProcP; @@ -170,7 +177,7 @@ namespace proc { , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) , NULL /* on open */ , NULL /* on close */ - , LUMIERA_INTERFACE_INLINE (startPlay, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", LumieraPlayProcess, (void), { if (!_instance) @@ -182,7 +189,7 @@ namespace proc { return static_cast (& (_instance->start())); } ) - , LUMIERA_INTERFACE_INLINE (pausePlay, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", void, (LumieraPlayProcess handle, bool doPlay), { if (!_instance) @@ -192,13 +199,12 @@ namespace proc { } REQUIRE (handle); - ProcP proc = dynamic_cast (handle); - ASSERT (proc); + ProcP proc = static_cast (handle); proc->pause(doPlay); } ) - , LUMIERA_INTERFACE_INLINE (terminate, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", void, (LumieraPlayProcess handle), { if (!_instance) @@ -208,24 +214,19 @@ namespace proc { } REQUIRE (handle); - ProcP proc = dynamic_cast (handle); - ASSERT (proc); + ProcP proc = static_cast (handle); UNIMPLEMENTED ("terminate a running playback process"); } ) - , LUMIERA_INTERFACE_INLINE (getFrame, LUIDGEN, + , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", void *, (LumieraPlayProcess handle), { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return 0; - } + //skipping full checks for performance reasons + REQUIRE (_instance && !lumiera_error_peek()); REQUIRE (handle); - ProcP proc = dynamic_cast (handle); - ASSERT (proc); + ProcP proc = static_cast (handle); return const_cast (proc->getFrame()); } @@ -241,7 +242,8 @@ namespace proc { DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) - : notifyTermination_(terminationHandle) + : error_("") + , notifyTermination_(terminationHandle) , implInstance_(this,_instance) , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) { diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp index 2a4aaf734..7610b91c3 100644 --- a/src/proc/dummy-player-service.hpp +++ b/src/proc/dummy-player-service.hpp @@ -44,12 +44,26 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include namespace proc { + using std::string; + using lumiera::Subsys; + class ProcessImpl + : public DummyPlayer::Process + { + void pause(bool doPlay); + void* const getFrame(); + + public: + ProcessImpl() {} + }; + + /****************************************************** * Actual implementation of the GuiNotification service * within the Lumiera GTK GUI. Creating an instance of @@ -75,8 +89,9 @@ namespace proc { * @todo actually implement multiple independent Playback processes! * @todo I am aware holding this object inline may cause a segfault at shutdown! */ - Process theProcess_; + ProcessImpl theProcess_; + string error_; Subsys::SigTerm notifyTermination_; @@ -93,7 +108,7 @@ namespace proc { public: DummyPlayerService(Subsys::SigTerm terminationHandle); - ~DummyPlayerService() { notifyTermination_(); } + ~DummyPlayerService() { notifyTermination_(&error_); } }; From 3dae60f559e22f954aac0be6ddd8642dd9f158e7 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 22 Jan 2009 17:29:17 +0100 Subject: [PATCH 11/18] add missing stubs to make it pass the compiler --- src/lib/singleton-ref.hpp | 2 +- src/proc/dummy-player-service.cpp | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/lib/singleton-ref.hpp b/src/lib/singleton-ref.hpp index f3fad3921..1adf14698 100644 --- a/src/lib/singleton-ref.hpp +++ b/src/lib/singleton-ref.hpp @@ -78,7 +78,7 @@ namespace lib { } - typedef void* _ThisType::*unspecified_bool_type; + typedef TY* _ThisType::*unspecified_bool_type; /** implicit conversion to "bool" */ operator unspecified_bool_type() const // never throws diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index 400bfafa4..f1f80409a 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -259,7 +259,33 @@ namespace proc { { return theDescriptor(); } - + + DummyPlayer::~DummyPlayer() { } ///< emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::Process::~Process() { } + + + + DummyPlayer::Process& + DummyPlayerService::start() + { + UNIMPLEMENTED ("initiate a new playback process"); + } + + + + void + ProcessImpl::pause(bool doPlay) + { + UNIMPLEMENTED ("pause playback"); + } + + + + void* const + ProcessImpl::getFrame() + { + UNIMPLEMENTED ("actually deliver a frame"); + } } // namespace proc From 7150ab9ee93941a99ec14079809a078427e3acbb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 22 Jan 2009 23:16:46 +0100 Subject: [PATCH 12/18] add implementation of PlayProcess logic --- src/common/interfaceproxy.cpp | 5 +++++ src/proc/dummy-player-service.cpp | 27 +++++++++++++++++++++++---- src/proc/dummy-player-service.hpp | 14 +++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/common/interfaceproxy.cpp b/src/common/interfaceproxy.cpp index 984555f28..bf7607f17 100644 --- a/src/common/interfaceproxy.cpp +++ b/src/common/interfaceproxy.cpp @@ -163,6 +163,11 @@ namespace lumiera { //----Proxy-Implementation-of-DummyPlayer-------- typedef proc::DummyPlayer::Process Process; + /** @note as an optimisation we hand out a direct reference + * to the implementing process object. While this ref could + * still be passed as handle to the C Language interface, using + * it directly within the client (=GUI) retains only on level + * of indirection, irrespective which interface is used. */ Process& start() { Process* pP = static_cast (_i_.startPlay()); diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp index f1f80409a..4984f9b45 100644 --- a/src/proc/dummy-player-service.cpp +++ b/src/proc/dummy-player-service.cpp @@ -247,7 +247,7 @@ namespace proc { , implInstance_(this,_instance) , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) { - INFO (operate, "GuiNotification Facade opened."); + INFO (operate, "DummyPlayer Facade opened."); } @@ -260,7 +260,8 @@ namespace proc { return theDescriptor(); } - DummyPlayer::~DummyPlayer() { } ///< emit the vtable here into this translation unit within liblumieraproc.so ... + // emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::~DummyPlayer() { } DummyPlayer::Process::~Process() { } @@ -268,7 +269,22 @@ namespace proc { DummyPlayer::Process& DummyPlayerService::start() { - UNIMPLEMENTED ("initiate a new playback process"); + REQUIRE (!theProcess_.isActive()); + theProcess_.setRate(25); + + return theProcess_; + } + + + + void + ProcessImpl::setRate (uint fps) + { + REQUIRE (fps==0 || fps_==0 ); + REQUIRE (fps==0 || !play_ ); + + fps_ = fps; + play_ = (fps != 0); } @@ -276,7 +292,8 @@ namespace proc { void ProcessImpl::pause(bool doPlay) { - UNIMPLEMENTED ("pause playback"); + REQUIRE (isActive()); + play_ = doPlay; } @@ -284,6 +301,8 @@ namespace proc { void* const ProcessImpl::getFrame() { + REQUIRE (isActive()); + UNIMPLEMENTED ("actually deliver a frame"); } diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp index 7610b91c3..f007e5cf4 100644 --- a/src/proc/dummy-player-service.hpp +++ b/src/proc/dummy-player-service.hpp @@ -59,8 +59,20 @@ namespace proc { void pause(bool doPlay); void* const getFrame(); + uint fps_; + bool play_; + public: - ProcessImpl() {} + ProcessImpl() : fps_(0), play_(false) {} + + /* Implementation-level API to be used By DummyPlayerService */ + + /** activate a playback process + * with given specification */ + void setRate (uint fps); + + bool isActive () { return fps_ != 0; } + bool isPlaying() { return play_; } }; From 791b09142a6aeb66ebf5cf4309fe888038fda3b0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 03:05:21 +0100 Subject: [PATCH 13/18] Refactoring: extract test image generation code into a separate class --- src/proc/dummy-player-service.cpp | 310 ----------------------- src/proc/dummy-player-service.hpp | 130 ---------- src/proc/play/dummy-image-generator.cpp | 163 ++++++++++++ src/proc/play/dummy-image-generator.hpp | 85 +++++++ src/proc/play/dummy-player-service.cpp | 317 ++++++++++++++++++++++++ src/proc/play/dummy-player-service.hpp | 133 ++++++++++ 6 files changed, 698 insertions(+), 440 deletions(-) delete mode 100644 src/proc/dummy-player-service.cpp delete mode 100644 src/proc/dummy-player-service.hpp create mode 100644 src/proc/play/dummy-image-generator.cpp create mode 100644 src/proc/play/dummy-image-generator.hpp create mode 100644 src/proc/play/dummy-player-service.cpp create mode 100644 src/proc/play/dummy-player-service.hpp diff --git a/src/proc/dummy-player-service.cpp b/src/proc/dummy-player-service.cpp deleted file mode 100644 index 4984f9b45..000000000 --- a/src/proc/dummy-player-service.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - DummyPlayerService - access point and service implementing a dummy test player - - Copyright (C) Lumiera.org - 2009, Hermann Vosseler - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -* *****************************************************/ - - -#include "proc/dummy-player-service.hpp" -#include "lib/singleton.hpp" - -extern "C" { -#include "common/interfacedescriptor.h" -} - -#include -#include - - -namespace proc { - - using std::string; - using lumiera::Subsys; - using boost::scoped_ptr; - - - namespace { // hidden local details of the service implementation.... - - /** details of how the DummyPlayer service can be started - * and used as independent "subsystem" within main() */ - class DummyPlayerSubsysDescriptor - : public Subsys - { - operator string () const { return "Dummy-Player"; } - - - bool - shouldStart (lumiera::Option&) - { - return false; // for now the DummyPlayerService only comes "up" as dependency, - } // but doesn't start as a subsystem on it's own. - - bool - start (lumiera::Option&, Subsys::SigTerm terminationHandle) - { - ASSERT (!thePlayer_); - - thePlayer_.reset (new DummyPlayerService (terminationHandle)); - return true; - } - - /** manages the actual (single) instance of the player service impl */ - scoped_ptr thePlayer_; - - - void - triggerShutdown () throw() - { - TODO ("implement waiting for any playback processes to terminate gracefully"); - //..... but this would require us to use a separate thread, so I skip it for now. - // Probably it's better design to manage the processes in a separate thread anyway... - - thePlayer_.reset(0); - } - - bool - checkRunningState () throw() - { - //note: not locking here... - return (thePlayer_); - } - }; - - lumiera::Singleton theDescriptor; - - - - - - /* ================== define an lumieraorg_GuiNotification instance ======================= */ - - LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 - ,lumieraorg_DummyPlayerFacade_descriptor - , NULL, NULL, NULL - , LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307", - const char*, (LumieraInterface ifa), - { (void)ifa; return "DummyPlayer"; } - ) - , LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232", - const char*, (LumieraInterface ifa), - { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } - ) - , LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200", - const char*, (LumieraInterface ifa), - { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} - ) - , LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165", - const char*, (LumieraInterface ifa), - { (void)ifa; return "0.1~pre"; } - ) - , LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105", - const char*, (LumieraInterface ifa), - { (void)ifa; return "Hermann Vosseler"; } - ) - , LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206", - const char*, (LumieraInterface ifa), - { (void)ifa; return "Ichthyostega@web.de"; } - ) - , LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210", - const char*, (LumieraInterface ifa), - { - (void)ifa; - return - "Copyright (C) Lumiera.org\n" - " 2009 Hermann Vosseler "; - } - ) - , LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060", - const char*, (LumieraInterface ifa), - { - (void)ifa; - return - "This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with this program; if not, write to the Free Software\n" - "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; - } - ) - , LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350", - int, (LumieraInterface ifa), - {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } - ) - , LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126", - int, (const char* a, const char* b), - {return 0;} ////////////////////////////////////////////TODO define version ordering - ) - ); - - - - - - using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; - typedef lib::SingletonRef::Accessor InstanceRef; - - InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... - - typedef DummyPlayer::Process* ProcP; - - - LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 - ,lumieraorg_DummyPlayerFacade - , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) - , NULL /* on open */ - , NULL /* on close */ - , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", - LumieraPlayProcess, (void), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return 0; - } - - return static_cast (& (_instance->start())); - } - ) - , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", - void, (LumieraPlayProcess handle, bool doPlay), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return; - } - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - proc->pause(doPlay); - } - ) - , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", - void, (LumieraPlayProcess handle), - { - if (!_instance) - { - lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); - return; - } - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - UNIMPLEMENTED ("terminate a running playback process"); - } - ) - , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", - void *, (LumieraPlayProcess handle), - { - //skipping full checks for performance reasons - REQUIRE (_instance && !lumiera_error_peek()); - - REQUIRE (handle); - ProcP proc = static_cast (handle); - - return const_cast (proc->getFrame()); - } - ) - ); - - - - - } // (End) hidden service impl details - - - - - DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) - : error_("") - , notifyTermination_(terminationHandle) - , implInstance_(this,_instance) - , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) - { - INFO (operate, "DummyPlayer Facade opened."); - } - - - - - /** @internal intended for use by main(). */ - Subsys& - DummyPlayer::getDescriptor() - { - return theDescriptor(); - } - - // emit the vtable here into this translation unit within liblumieraproc.so ... - DummyPlayer::~DummyPlayer() { } - DummyPlayer::Process::~Process() { } - - - - DummyPlayer::Process& - DummyPlayerService::start() - { - REQUIRE (!theProcess_.isActive()); - theProcess_.setRate(25); - - return theProcess_; - } - - - - void - ProcessImpl::setRate (uint fps) - { - REQUIRE (fps==0 || fps_==0 ); - REQUIRE (fps==0 || !play_ ); - - fps_ = fps; - play_ = (fps != 0); - } - - - - void - ProcessImpl::pause(bool doPlay) - { - REQUIRE (isActive()); - play_ = doPlay; - } - - - - void* const - ProcessImpl::getFrame() - { - REQUIRE (isActive()); - - UNIMPLEMENTED ("actually deliver a frame"); - } - - -} // namespace proc diff --git a/src/proc/dummy-player-service.hpp b/src/proc/dummy-player-service.hpp deleted file mode 100644 index f007e5cf4..000000000 --- a/src/proc/dummy-player-service.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player - - - Copyright (C) Lumiera.org - 2009, Hermann Vosseler - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file notification-service.hpp - ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. - ** The purpose of this service is to push state update and notification of events from the lower - ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events - ** within the lower layers. - ** - ** This service is the implementation of a layer separation facade interface. Clients should use - ** gui::GuiNotification#facade to access this service. This header defines the interface used - ** to \em provide this service, not to access it. - ** - ** @see gui::GuiFacade - ** @see guifacade.cpp starting this service - */ - - -#ifndef PROC_DUMMYPLAYER_SERVICE_H -#define PROC_DUMMYPLAYER_SERVICE_H - - -#include "include/dummy-player-facade.h" -#include "common/instancehandle.hpp" -#include "lib/singleton-ref.hpp" - -#include - - -namespace proc { - - using std::string; - using lumiera::Subsys; - - - class ProcessImpl - : public DummyPlayer::Process - { - void pause(bool doPlay); - void* const getFrame(); - - uint fps_; - bool play_; - - public: - ProcessImpl() : fps_(0), play_(false) {} - - /* Implementation-level API to be used By DummyPlayerService */ - - /** activate a playback process - * with given specification */ - void setRate (uint fps); - - bool isActive () { return fps_ != 0; } - bool isPlaying() { return play_; } - }; - - - /****************************************************** - * Actual implementation of the GuiNotification service - * within the Lumiera GTK GUI. Creating an instance of - * this class automatically registers the interface - * with the Lumiera Interface/Plugin system and creates - * a forwarding proxy within the application core to - * route calls through this interface. - * - * @todo the ctor of this class should take references - * to any internal service providers within the - * GUI which are needed to implement the service. - */ - class DummyPlayerService - : public DummyPlayer - { - - /* === Implementation of the Facade Interface === */ - - Process& start(); - - - /** for now we use an single inline Process... - * @todo actually implement multiple independent Playback processes! - * @todo I am aware holding this object inline may cause a segfault at shutdown! - */ - ProcessImpl theProcess_; - - string error_; - Subsys::SigTerm notifyTermination_; - - - - /* === Interface Lifecycle === */ - - typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) - , DummyPlayer - > ServiceInstanceHandle; - - lib::SingletonRef implInstance_; - ServiceInstanceHandle serviceInstance_; - - public: - DummyPlayerService(Subsys::SigTerm terminationHandle); - - ~DummyPlayerService() { notifyTermination_(&error_); } - - }; - - - -} // namespace proc -#endif diff --git a/src/proc/play/dummy-image-generator.cpp b/src/proc/play/dummy-image-generator.cpp new file mode 100644 index 000000000..ba1cef9c5 --- /dev/null +++ b/src/proc/play/dummy-image-generator.cpp @@ -0,0 +1,163 @@ +/* + DummyImageGenerator - creating test output frames for simulated playback + + Copyright (C) Lumiera.org + 2009, Joel Holdsworth , + Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/play/dummy-image-generator.hpp" + + +namespace proc { + namespace play { + + + + namespace { // implementation details + + + typedef unsigned char byte; + + inline int + clamp (const int &val, const int &maxval, const int &minval) + { + if(val > maxval) return maxval; + if(val < minval) return minval; + return val; + } + + inline void + rgb_to_yuv (int r, int g, int b, byte &y, byte &u, byte &v) + { + // This code isn't great, but it does the job + y = (byte)clamp((299 * r + 587 * g + 114 * b) / 1000, 235, 16); + v = (byte)clamp((500 * r - 419 * g - 81 * b) / 1000 + 127, 255, 0); + u = (byte)clamp((-169 * r - 331 * g + 500 * b) / 1000 + 127, 255, 0); + } + + + void + rgb_buffer_to_yuy2 (unsigned char *in, unsigned char *out) + { + for (uint i = 0; i < 320*240*2; i+=4) + { + byte y0, u0, v0; + const byte r0 = *(in++); + const byte g0 = *(in++); + const byte b0 = *(in++); + rgb_to_yuv(r0, g0, b0, y0, u0, v0); + + byte y1, u1, v1; + const byte r1 = *(in++); + const byte g1 = *(in++); + const byte b1 = *(in++); + rgb_to_yuv(r1, g1, b1, y1, u1, v1); + + out[i] = y0; + out[i + 1] = u0; + out[i + 2] = y1; + out[i + 3] = v0; + } } + + + } // (End) implementation details + + + + + DummyImageGenerator::DummyImageGenerator(uint fps) + : current_(0) + , frame_(0) + , fps_(fps) + { } + + + void * const + DummyImageGenerator::next() + { + + ++frame_; + if(frame_ > 2 * fps_) + frame_ = 0; + + if(frame_ < 1 * fps_) + { + // create random snow... + for(int i = 0; i < 320*240*3; i+=3) + { + byte value ( rand() ); + buf_[i] = value; + buf_[i+1] = value; + buf_[i+2] = value; + } + } + else + { // create a colour strip pattern + typedef unsigned char Row[320 * 3]; + + unsigned char * row = buf_; + + // create a colour strip pattern in the first row... + for(int x = 0; x < 320; ++x) + { + byte &r = row[x*3]; + byte &g = row[x*3+1]; + byte &b = row[x*3+2]; + + if (x < 1*320/7) r = 0xC0, g = 0xC0, b = 0xC0; + else if(x < 2*320/7) r = 0xC0, g = 0xC0, b = 0x00; + else if(x < 3*320/7) r = 0x00, g = 0xC0, b = 0xC0; + else if(x < 4*320/7) r = 0x00, g = 0xC0, b = 0x00; + else if(x < 5*320/7) r = 0xC0, g = 0x00, b = 0xC0; + else if(x < 6*320/7) r = 0xC0, g = 0x00, b = 0x00; + else r = 0x00, g = 0x00, b = 0xC0; + } + + // fill remaining rows of the frame with the same pattern + for(int y = 1; y < 240; ++y) + memcpy(buf_ + y*sizeof(Row), row, sizeof(Row)); + + } + + // select output buffer to return + unsigned char * outBuff; + + if (!current_) + { + outBuff = outFrame_A_; + current_= 1; + } + else + { + outBuff = outFrame_B_; + current_= 0; + } + + rgb_buffer_to_yuy2(buf_, outBuff); + return outBuff; + + } + + + + + } // namespace play + +} // namespace proc diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/play/dummy-image-generator.hpp new file mode 100644 index 000000000..0cab60404 --- /dev/null +++ b/src/proc/play/dummy-image-generator.hpp @@ -0,0 +1,85 @@ +/* + DUMMY-IMAGE-GENERATOR.hpp - creating test output frames for simulated playback + + Copyright (C) Lumiera.org + 2009, Joel Holdsworth , + Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file dummy-image-generator.hpp + ** Generator for test dummy video frames to simulate playback of rendered output. + ** As of 1/2009 the render engine and source reading functions are not ready yet. + ** So, in order to learn how to build up the GUI/Playback interfaces, we use + ** this dummy image generator to create visible output. First implemented + ** by Joel within PlaybackController, then factored out into a separate + ** dummy playback service. + ** + ** @see gui::controller::PlaybackController + ** @see proc::play::DummyPlayerService + ** + */ + + +#ifndef PROC_PLAY_DUMMY_IMAGE_GENERATOR_H +#define PROC_PLAY_DUMMY_IMAGE_GENERATOR_H + + +#include "lib/error.hpp" + + +namespace proc { + namespace play { + + + class DummyImageGenerator + { + + unsigned char buf_[320 * 240 * 3]; ///< working buffer for next frame + + unsigned char outFrame_A_[320 * 240 * 4]; ///< output frame 1 + unsigned char outFrame_B_[320 * 240 * 4]; ///< output frame 2 + + uint current_; + uint frame_; + uint fps_; + + + public: + DummyImageGenerator(uint fps); + + ~DummyImageGenerator() { } + + /** generate the next frame and + * occupy the alternate buffer. + * @return the buffer containing the new frame + */ + void * const next(); + + + private: + + }; + + + + + } // namespace play + +} // namespace proc +#endif // PROC_PLAY_DUMMY_IMAGE_GENERATOR_H + diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp new file mode 100644 index 000000000..2d86a07c5 --- /dev/null +++ b/src/proc/play/dummy-player-service.cpp @@ -0,0 +1,317 @@ +/* + DummyPlayerService - access point and service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "proc/play/dummy-player-service.hpp" +#include "lib/singleton.hpp" + +extern "C" { +#include "common/interfacedescriptor.h" +} + +#include +#include + + +namespace proc { + namespace play{ + + using std::string; + using lumiera::Subsys; + using boost::scoped_ptr; + + + namespace { // hidden local details of the service implementation.... + + /** details of how the DummyPlayer service can be started + * and used as independent "subsystem" within main() */ + class DummyPlayerSubsysDescriptor + : public Subsys + { + operator string () const { return "Dummy-Player"; } + + + bool + shouldStart (lumiera::Option&) + { + return false; // for now the DummyPlayerService only comes "up" as dependency, + } // but doesn't start as a subsystem on it's own. + + bool + start (lumiera::Option&, Subsys::SigTerm terminationHandle) + { + ASSERT (!thePlayer_); + + thePlayer_.reset (new DummyPlayerService (terminationHandle)); + return true; + } + + /** manages the actual (single) instance of the player service impl */ + scoped_ptr thePlayer_; + + + void + triggerShutdown () throw() + { + TODO ("implement waiting for any playback processes to terminate gracefully"); + //..... but this would require us to use a separate thread, so I skip it for now. + // Probably it's better design to manage the processes in a separate thread anyway... + + thePlayer_.reset(0); + } + + bool + checkRunningState () throw() + { + //note: not locking here... + return (thePlayer_); + } + }; + + lumiera::Singleton theDescriptor; + + + + + + /* ================== define an lumieraorg_GuiNotification instance ======================= */ + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_interfacedescriptor, 0 + ,lumieraorg_DummyPlayerFacade_descriptor + , NULL, NULL, NULL + , LUMIERA_INTERFACE_INLINE (name, "\305\162\202\240\075\316\146\100\314\152\075\343\372\065\226\307", + const char*, (LumieraInterface ifa), + { (void)ifa; return "DummyPlayer"; } + ) + , LUMIERA_INTERFACE_INLINE (brief, "\317\045\366\076\064\072\156\274\220\346\262\207\062\367\057\232", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Proc Interface: dummy player to test integration with the GUI"; } + ) + , LUMIERA_INTERFACE_INLINE (homepage, "\136\225\033\362\161\251\300\256\117\072\171\102\235\004\235\200", + const char*, (LumieraInterface ifa), + { (void)ifa; return "http://www.lumiera.org/develompent.html" ;} + ) + , LUMIERA_INTERFACE_INLINE (version, "\212\146\344\127\124\116\101\205\211\174\322\241\162\122\023\165", + const char*, (LumieraInterface ifa), + { (void)ifa; return "0.1~pre"; } + ) + , LUMIERA_INTERFACE_INLINE (author, "\064\226\072\300\054\345\042\357\337\226\155\025\306\051\117\105", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Hermann Vosseler"; } + ) + , LUMIERA_INTERFACE_INLINE (email, "\041\075\220\112\246\304\261\135\003\135\060\202\230\327\303\206", + const char*, (LumieraInterface ifa), + { (void)ifa; return "Ichthyostega@web.de"; } + ) + , LUMIERA_INTERFACE_INLINE (copyright, "\232\305\163\271\174\025\270\075\012\201\331\256\327\375\066\210", + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "Copyright (C) Lumiera.org\n" + " 2009 Hermann Vosseler "; + } + ) + , LUMIERA_INTERFACE_INLINE (license, "\136\136\073\173\145\357\151\062\040\013\323\272\051\352\305\060", + const char*, (LumieraInterface ifa), + { + (void)ifa; + return + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation; either version 2 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" + "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"; + } + ) + , LUMIERA_INTERFACE_INLINE (state, "\224\251\004\001\165\140\116\246\126\311\115\234\023\026\331\350", + int, (LumieraInterface ifa), + {(void)ifa; return LUMIERA_INTERFACE_EXPERIMENTAL; } + ) + , LUMIERA_INTERFACE_INLINE (versioncmp, "\267\155\303\046\353\222\323\014\145\027\043\100\370\311\257\126", + int, (const char* a, const char* b), + {return 0;} ////////////////////////////////////////////TODO define version ordering + ) + ); + + + + + + using lumiera::facade::LUMIERA_ERROR_FACADE_LIFECYCLE; + typedef lib::SingletonRef::Accessor InstanceRef; + + InstanceRef _instance; ///< a backdoor for the C Language impl to access the actual DummyPlayer implementation... + + typedef DummyPlayer::Process* ProcP; + + + LUMIERA_INTERFACE_INSTANCE (lumieraorg_DummyPlayer, 0 + ,lumieraorg_DummyPlayerFacade + , LUMIERA_INTERFACE_REF(lumieraorg_interfacedescriptor, 0, lumieraorg_DummyPlayerFacade_descriptor) + , NULL /* on open */ + , NULL /* on close */ + , LUMIERA_INTERFACE_INLINE (startPlay, "\143\323\102\155\051\006\235\004\037\310\354\121\176\142\342\210", + LumieraPlayProcess, (void), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return 0; + } + + return static_cast (& (_instance->start())); + } + ) + , LUMIERA_INTERFACE_INLINE (pausePlay, "\275\157\316\220\210\053\226\134\057\016\273\265\240\053\112\307", + void, (LumieraPlayProcess handle, bool doPlay), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = static_cast (handle); + + proc->pause(doPlay); + } + ) + , LUMIERA_INTERFACE_INLINE (terminate, "\005\265\115\021\076\143\010\215\373\252\370\174\235\136\340\004", + void, (LumieraPlayProcess handle), + { + if (!_instance) + { + lumiera_error_set(LUMIERA_ERROR_FACADE_LIFECYCLE, 0); + return; + } + + REQUIRE (handle); + ProcP proc = static_cast (handle); + + UNIMPLEMENTED ("terminate a running playback process"); + } + ) + , LUMIERA_INTERFACE_INLINE (getFrame, "\230\130\101\300\047\065\170\052\226\164\026\112\150\166\074\134", + void *, (LumieraPlayProcess handle), + { + //skipping full checks for performance reasons + REQUIRE (_instance && !lumiera_error_peek()); + + REQUIRE (handle); + ProcP proc = static_cast (handle); + + return const_cast (proc->getFrame()); + } + ) + ); + + + + + } // (End) hidden service impl details + + + + + DummyPlayerService::DummyPlayerService (Subsys::SigTerm terminationHandle) + : error_("") + , notifyTermination_(terminationHandle) + , implInstance_(this,_instance) + , serviceInstance_( LUMIERA_INTERFACE_REF (lumieraorg_DummyPlayer, 0, lumieraorg_DummyPlayerFacade)) + { + INFO (operate, "DummyPlayer Facade opened."); + } + + + + + DummyPlayer::Process& + DummyPlayerService::start() + { + REQUIRE (!theProcess_.isActive()); + theProcess_.setRate(25); + + return theProcess_; + } + + + + void + ProcessImpl::setRate (uint fps) + { + REQUIRE (fps==0 || fps_==0 ); + REQUIRE (fps==0 || !play_ ); + + fps_ = fps; + play_ = (fps != 0); + } + + + + void + ProcessImpl::pause(bool doPlay) + { + REQUIRE (isActive()); + play_ = doPlay; + } + + + + void* const + ProcessImpl::getFrame() + { + REQUIRE (isActive()); + + UNIMPLEMENTED ("actually deliver a frame"); + } + + + + } // namespace play + + + + /** @internal intended for use by main(). */ + lumiera::Subsys& + DummyPlayer::getDescriptor() + { + return play::theDescriptor(); + } + + // emit the vtable here into this translation unit within liblumieraproc.so ... + DummyPlayer::~DummyPlayer() { } + DummyPlayer::Process::~Process() { } + + + + +} // namespace proc diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp new file mode 100644 index 000000000..1d7c9f9aa --- /dev/null +++ b/src/proc/play/dummy-player-service.hpp @@ -0,0 +1,133 @@ +/* + DUMMY-PLAYER-SERVICE.hpp - service implementing a dummy test player + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file notification-service.hpp + ** A public service provided by the GUI, implementing the gui::GuiNotification facade interface. + ** The purpose of this service is to push state update and notification of events from the lower + ** layers into the Lumiera GUI. Typically, this happens asynchronously and triggered by events + ** within the lower layers. + ** + ** This service is the implementation of a layer separation facade interface. Clients should use + ** gui::GuiNotification#facade to access this service. This header defines the interface used + ** to \em provide this service, not to access it. + ** + ** @see gui::GuiFacade + ** @see guifacade.cpp starting this service + */ + + +#ifndef PROC_DUMMYPLAYER_SERVICE_H +#define PROC_DUMMYPLAYER_SERVICE_H + + +#include "include/dummy-player-facade.h" +#include "common/instancehandle.hpp" +#include "lib/singleton-ref.hpp" + +#include + + +namespace proc { + namespace play { + + using std::string; + using lumiera::Subsys; + + + class ProcessImpl + : public DummyPlayer::Process + { + void pause(bool doPlay); + void* const getFrame(); + + uint fps_; + bool play_; + + public: + ProcessImpl() : fps_(0), play_(false) {} + + /* Implementation-level API to be used By DummyPlayerService */ + + /** activate a playback process + * with given specification */ + void setRate (uint fps); + + bool isActive () { return fps_ != 0; } + bool isPlaying() { return play_; } + }; + + + /****************************************************** + * Actual implementation of the GuiNotification service + * within the Lumiera GTK GUI. Creating an instance of + * this class automatically registers the interface + * with the Lumiera Interface/Plugin system and creates + * a forwarding proxy within the application core to + * route calls through this interface. + * + * @todo the ctor of this class should take references + * to any internal service providers within the + * GUI which are needed to implement the service. + */ + class DummyPlayerService + : public DummyPlayer + { + + /* === Implementation of the Facade Interface === */ + + Process& start(); + + + /** for now we use an single inline Process... + * @todo actually implement multiple independent Playback processes! + * @todo I am aware holding this object inline may cause a segfault at shutdown! + */ + ProcessImpl theProcess_; + + string error_; + Subsys::SigTerm notifyTermination_; + + + + /* === Interface Lifecycle === */ + + typedef lumiera::InstanceHandle< LUMIERA_INTERFACE_INAME(lumieraorg_DummyPlayer, 0) + , DummyPlayer + > ServiceInstanceHandle; + + lib::SingletonRef implInstance_; + ServiceInstanceHandle serviceInstance_; + + public: + DummyPlayerService(Subsys::SigTerm terminationHandle); + + ~DummyPlayerService() { notifyTermination_(&error_); } + + }; + + + + + } // namespace play + +} // namespace proc +#endif From 6c3492396c6d32b28b5f63d94d89c392503e052f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 04:15:58 +0100 Subject: [PATCH 14/18] Refactoring: switch gui::PlaybackController to use the player service --- src/gui/controller/controller.hpp | 5 +- src/gui/controller/playback-controller.cpp | 132 ++++++--------------- src/gui/controller/playback-controller.hpp | 14 ++- src/proc/play/dummy-image-generator.cpp | 9 +- src/proc/play/dummy-image-generator.hpp | 4 + src/proc/play/dummy-player-service.cpp | 10 +- src/proc/play/dummy-player-service.hpp | 11 +- 7 files changed, 82 insertions(+), 103 deletions(-) diff --git a/src/gui/controller/controller.hpp b/src/gui/controller/controller.hpp index 27f185e97..594f5e19e 100644 --- a/src/gui/controller/controller.hpp +++ b/src/gui/controller/controller.hpp @@ -23,11 +23,12 @@ ** This file contains the definition of the controller object */ -#include "playback-controller.hpp" - #ifndef CONTROLLER_HPP #define CONTROLLER_HPP +#include "playback-controller.hpp" + + namespace gui { namespace model { diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index d68373025..90b3ec29d 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -20,32 +20,46 @@ * *****************************************************/ -#include "playback-controller.hpp" -#include "../gtk-lumiera.hpp" +#include "gui/controller/playback-controller.hpp" +#include "lib/error.hpp" +#include namespace gui { namespace controller { PlaybackController::PlaybackController() : finish_playback_thread(false), - playing(false) -{ - start_playback_thread(); -} + playing(false), + playHandle(0) +{ } + PlaybackController::~PlaybackController() { mutex.lock(); finish_playback_thread = true; mutex.unlock(); - thread->join(); + if (thread) + thread->join(); } void PlaybackController::play() { Glib::Mutex::Lock lock(mutex); - playing = true; + try + { + playHandle = & (proc::DummyPlayer::facade().start()); + start_playback_thread(); + playing = true; + + } + catch (lumiera::error::State& err) + { + WARN (operate, "failed to start playback: %s" ,err.what()); + lumiera_error(); + playing = false; + } } void @@ -53,6 +67,8 @@ PlaybackController::pause() { Glib::Mutex::Lock lock(mutex); playing = false; + if (playHandle) + playHandle->pause(true); } void @@ -60,6 +76,7 @@ PlaybackController::stop() { Glib::Mutex::Lock lock(mutex); playing = false; + // TODO: stop player somehow? } bool @@ -97,108 +114,37 @@ PlaybackController::playback_thread() if(is_playing()) pull_frame(); - + + ////////////////////////////////TODO: usleep Glib::Thread::yield(); } } -typedef unsigned char byte; - -inline int -clamp(const int &val, const int &maxval, const int &minval) -{ - if(val > maxval) return maxval; - if(val < minval) return minval; - return val; -} - -inline void -rgb_to_yuv(int r, int g, int b, byte &y, byte &u, byte &v) -{ - // This code isn't great, but it does the job - y = (byte)clamp((299 * r + 587 * g + 114 * b) / 1000, 235, 16); - v = (byte)clamp((500 * r - 419 * g - 81 * b) / 1000 + 127, 255, 0); - u = (byte)clamp((-169 * r - 331 * g + 500 * b) / 1000 + 127, 255, 0); -} - -void rgb_buffer_to_yuy2(unsigned char *in, unsigned char *out) -{ - for(int i = 0; i < 320*240*2; i+=4) - { - byte y0, u0, v0; - const byte r0 = *(in++); - const byte g0 = *(in++); - const byte b0 = *(in++); - rgb_to_yuv(r0, g0, b0, y0, u0, v0); - - byte y1, u1, v1; - const byte r1 = *(in++); - const byte g1 = *(in++); - const byte b1 = *(in++); - rgb_to_yuv(r1, g1, b1, y1, u1, v1); - - out[i] = y0; - out[i + 1] = u0; - out[i + 2] = y1; - out[i + 3] = v0; - } -} void PlaybackController::pull_frame() { - static int frame = 0; - unsigned char in[320 * 240 * 3]; + REQUIRE (is_playing()); + REQUIRE (playHandle); - frame--; + unsigned char * newBuffer = reinterpret_cast (playHandle->getFrame()); - if(frame <= 0) - frame = 200; - - if(frame > 150) - { - for(int i = 0; i < 320*240*3; i+=3) - { - byte value = (byte)rand(); - in[i] = value; - in[i+1] = value; - in[i+2] = value; - } - } - else - { - unsigned char row[320 * 3]; - - for(int x = 0; x < 320; x++) - { - byte &r = row[x*3]; - byte &g = row[x*3+1]; - byte &b = row[x*3+2]; - - if(x < 1*320/7) r = 0xC0, g = 0xC0, b = 0xC0; - else if(x < 2*320/7) r = 0xC0, g = 0xC0, b = 0x00; - else if(x < 3*320/7) r = 0x00, g = 0xC0, b = 0xC0; - else if(x < 4*320/7) r = 0x00, g = 0xC0, b = 0x00; - else if(x < 5*320/7) r = 0xC0, g = 0x00, b = 0xC0; - else if(x < 6*320/7) r = 0xC0, g = 0x00, b = 0x00; - else r = 0x00, g = 0x00, b = 0xC0; - } - - for(int y = 0; y < 240; y++) + if (newBuffer != currentBuffer) { - memcpy(in + y*320*3, row, sizeof(row)); + currentBuffer = newBuffer; + dispatcher.emit(); + } + else + { + TRACE (render, "frame dropped?"); } - } - - rgb_buffer_to_yuy2(in, buffer); - - dispatcher.emit(); } + void PlaybackController::on_frame() { - frame_signal.emit(buffer); + frame_signal.emit(currentBuffer); } } // namespace controller diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 9333fcbc2..52a7d0b42 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -23,16 +23,20 @@ ** This file contains the definition of the playback controller object */ -#include -#include - #ifndef PLAYBACK_CONTROLLER_HPP #define PLAYBACK_CONTROLLER_HPP +#include "include/dummy-player-facade.h" + +#include +#include +#include + namespace gui { namespace controller { class PlaybackController + : boost::noncopyable { public: @@ -72,7 +76,9 @@ private: volatile bool playing; - unsigned char buffer[320 * 240 * 4]; + proc::DummyPlayer::Process *playHandle; + + unsigned char * currentBuffer; sigc::signal frame_signal; }; diff --git a/src/proc/play/dummy-image-generator.cpp b/src/proc/play/dummy-image-generator.cpp index ba1cef9c5..29d58a1ac 100644 --- a/src/proc/play/dummy-image-generator.cpp +++ b/src/proc/play/dummy-image-generator.cpp @@ -154,7 +154,14 @@ namespace proc { return outBuff; } - + + + void * const + DummyImageGenerator::current() + { + if (!current_) return outFrame_A_; + else return outFrame_B_; + } diff --git a/src/proc/play/dummy-image-generator.hpp b/src/proc/play/dummy-image-generator.hpp index 0cab60404..e24a4592e 100644 --- a/src/proc/play/dummy-image-generator.hpp +++ b/src/proc/play/dummy-image-generator.hpp @@ -69,6 +69,10 @@ namespace proc { * @return the buffer containing the new frame */ void * const next(); + + /** just re-return a pointer to the current frame + * without generating any new image data */ + void * const current(); private: diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 2d86a07c5..378d7d7ff 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -22,6 +22,7 @@ #include "proc/play/dummy-player-service.hpp" +#include "proc/play/dummy-image-generator.hpp" #include "lib/singleton.hpp" extern "C" { @@ -273,6 +274,9 @@ namespace proc { fps_ = fps; play_ = (fps != 0); + + if (play_) + imageGen_.reset(new DummyImageGenerator(fps)); } @@ -290,8 +294,12 @@ namespace proc { ProcessImpl::getFrame() { REQUIRE (isActive()); + ASSERT (imageGen_); - UNIMPLEMENTED ("actually deliver a frame"); + if (play_) + return imageGen_->next(); + else + return imageGen_->current(); } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 1d7c9f9aa..8f7a045e6 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -43,6 +43,7 @@ #include "common/instancehandle.hpp" #include "lib/singleton-ref.hpp" +#include #include @@ -53,6 +54,9 @@ namespace proc { using lumiera::Subsys; + class DummyImageGenerator; + + class ProcessImpl : public DummyPlayer::Process { @@ -60,10 +64,13 @@ namespace proc { void* const getFrame(); uint fps_; - bool play_; + bool play_; + + boost::scoped_ptr imageGen_; + public: - ProcessImpl() : fps_(0), play_(false) {} + ProcessImpl() : fps_(0), play_(false), imageGen_(0) {} /* Implementation-level API to be used By DummyPlayerService */ From 48a632434a76c239569b68711a16ee3f0d3c04cd Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 19:57:12 +0100 Subject: [PATCH 15/18] switch from Glib::Mutex to an object monitor (using LumieraMutex) --- src/gui/controller/playback-controller.cpp | 21 +++++++++++++-------- src/gui/controller/playback-controller.hpp | 14 ++++++++++---- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 90b3ec29d..27028dbfb 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -36,9 +36,7 @@ PlaybackController::PlaybackController() : PlaybackController::~PlaybackController() { - mutex.lock(); - finish_playback_thread = true; - mutex.unlock(); + quit_playback_thread(); if (thread) thread->join(); } @@ -46,7 +44,7 @@ PlaybackController::~PlaybackController() void PlaybackController::play() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); try { playHandle = & (proc::DummyPlayer::facade().start()); @@ -65,7 +63,7 @@ PlaybackController::play() void PlaybackController::pause() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); playing = false; if (playHandle) playHandle->pause(true); @@ -74,7 +72,7 @@ PlaybackController::pause() void PlaybackController::stop() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); playing = false; // TODO: stop player somehow? } @@ -82,7 +80,7 @@ PlaybackController::stop() bool PlaybackController::is_playing() { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); return playing; } @@ -94,6 +92,13 @@ PlaybackController::start_playback_thread() this, &PlaybackController::playback_thread), true); } +void +PlaybackController::quit_playback_thread() +{ + Lock sync(this); + finish_playback_thread = true; +} + void PlaybackController::attach_viewer( const sigc::slot& on_frame) @@ -107,7 +112,7 @@ PlaybackController::playback_thread() for(;;) { { - Glib::Mutex::Lock lock(mutex); + Lock sync(this); if(finish_playback_thread) return; } diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 52a7d0b42..142737dfd 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -27,16 +27,22 @@ #define PLAYBACK_CONTROLLER_HPP #include "include/dummy-player-facade.h" +#include "lib/sync.hpp" #include #include #include namespace gui { -namespace controller { +namespace controller { + +using lib::Sync; +using lib::NonrecursiveLock_NoWait; + class PlaybackController - : boost::noncopyable + : boost::noncopyable, + public Sync { public: @@ -58,6 +64,8 @@ private: void start_playback_thread(); + void quit_playback_thread(); + void playback_thread(); void pull_frame(); @@ -68,8 +76,6 @@ private: Glib::Thread *thread; - Glib::StaticMutex mutex; - Glib::Dispatcher dispatcher; volatile bool finish_playback_thread; From 58512e8a340359703a5015ef9250da726a51fb1a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 23 Jan 2009 20:23:24 +0100 Subject: [PATCH 16/18] First version working again. Thread handling is not stable and stop hangs though --- src/gui/controller/playback-controller.cpp | 29 ++++++++++++++-------- src/gui/controller/playback-controller.hpp | 2 +- src/lumiera/main.cpp | 3 +++ src/proc/play/dummy-player-service.cpp | 8 +++--- src/proc/play/dummy-player-service.hpp | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index 27028dbfb..bad1ebcc1 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -28,6 +28,7 @@ namespace gui { namespace controller { PlaybackController::PlaybackController() : + thread(0), finish_playback_thread(false), playing(false), playHandle(0) @@ -36,9 +37,7 @@ PlaybackController::PlaybackController() : PlaybackController::~PlaybackController() { - quit_playback_thread(); - if (thread) - thread->join(); + end_playback_thread(); } void @@ -47,10 +46,15 @@ PlaybackController::play() Lock sync(this); try { - playHandle = & (proc::DummyPlayer::facade().start()); - start_playback_thread(); - playing = true; - + if (playing && thread && playHandle) playHandle->pause(false); + else + { + playHandle = & (proc::DummyPlayer::facade().start()); + if (thread) + end_playback_thread(); + start_playback_thread(); + playing = true; + } } catch (lumiera::error::State& err) { @@ -74,6 +78,8 @@ PlaybackController::stop() { Lock sync(this); playing = false; + end_playback_thread(); + playHandle = 0; // TODO: stop player somehow? } @@ -88,15 +94,19 @@ void PlaybackController::start_playback_thread() { dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame)); + finish_playback_thread = false; thread = Glib::Thread::create (sigc::mem_fun( this, &PlaybackController::playback_thread), true); } void -PlaybackController::quit_playback_thread() +PlaybackController::end_playback_thread() { Lock sync(this); finish_playback_thread = true; + if (thread) + thread->join(); + thread = 0; } void @@ -120,8 +130,7 @@ PlaybackController::playback_thread() if(is_playing()) pull_frame(); - ////////////////////////////////TODO: usleep - Glib::Thread::yield(); + usleep(40000); // ca 25 frames pre second } } diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 142737dfd..9cab6d968 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -64,7 +64,7 @@ private: void start_playback_thread(); - void quit_playback_thread(); + void end_playback_thread(); void playback_thread(); diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index 9d0317102..05e732a9f 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -30,6 +30,7 @@ #include "backend/enginefacade.hpp" #include "backend/netnodefacade.hpp" #include "backend/scriptrunnerfacade.hpp" +#include "include/dummy-player-facade.h" #include "proc/facade.hpp" #include "gui/guifacade.hpp" @@ -42,6 +43,7 @@ namespace { Subsys& engine = backend::EngineFacade::getDescriptor(); Subsys& netNode = backend::NetNodeFacade::getDescriptor(); Subsys& script = backend::ScriptRunnerFacade::getDescriptor(); + Subsys& player = proc::DummyPlayer::getDescriptor(); Subsys& builder = proc::Facade::getBuilderDescriptor(); Subsys& session = proc::Facade::getSessionDescriptor(); Subsys& lumigui = gui::GuiFacade::getDescriptor(); @@ -66,6 +68,7 @@ main (int argc, const char* argv[]) netNode.depends (engine); // lumigui.depends (session); //////TODO commented out in order to be able to start up a dummy GuiStarterPlugin // lumigui.depends (engine); + lumigui.depends (player); script.depends (session); script.depends (engine); diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 378d7d7ff..4ec1a87ad 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -258,7 +258,7 @@ namespace proc { DummyPlayer::Process& DummyPlayerService::start() { - REQUIRE (!theProcess_.isActive()); + // REQUIRE (!theProcess_.isActive()); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! theProcess_.setRate(25); return theProcess_; @@ -269,7 +269,7 @@ namespace proc { void ProcessImpl::setRate (uint fps) { - REQUIRE (fps==0 || fps_==0 ); + // REQUIRE (fps==0 || fps_==0 ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! REQUIRE (fps==0 || !play_ ); fps_ = fps; @@ -282,10 +282,10 @@ namespace proc { void - ProcessImpl::pause(bool doPlay) + ProcessImpl::pause(bool doPause) { REQUIRE (isActive()); - play_ = doPlay; + play_ = !doPause; } diff --git a/src/proc/play/dummy-player-service.hpp b/src/proc/play/dummy-player-service.hpp index 8f7a045e6..ae8b3161e 100644 --- a/src/proc/play/dummy-player-service.hpp +++ b/src/proc/play/dummy-player-service.hpp @@ -60,7 +60,7 @@ namespace proc { class ProcessImpl : public DummyPlayer::Process { - void pause(bool doPlay); + void pause(bool doPause); void* const getFrame(); uint fps_; From e524e8c52866e365add78e765a5ae7dc905caca3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 24 Jan 2009 21:33:41 +0100 Subject: [PATCH 17/18] Fix the most obvious lockups ... but the design still doesn't feel right for me! --- src/gui/controller/playback-controller.cpp | 56 +++++++++++++--------- src/gui/controller/playback-controller.hpp | 4 +- src/proc/play/dummy-player-service.cpp | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/gui/controller/playback-controller.cpp b/src/gui/controller/playback-controller.cpp index bad1ebcc1..f360ca6a5 100644 --- a/src/gui/controller/playback-controller.cpp +++ b/src/gui/controller/playback-controller.cpp @@ -43,25 +43,29 @@ PlaybackController::~PlaybackController() void PlaybackController::play() { - Lock sync(this); - try + if (playing && thread && playHandle) { - if (playing && thread && playHandle) playHandle->pause(false); - else - { - playHandle = & (proc::DummyPlayer::facade().start()); - if (thread) - end_playback_thread(); - start_playback_thread(); - playing = true; - } - } - catch (lumiera::error::State& err) - { - WARN (operate, "failed to start playback: %s" ,err.what()); - lumiera_error(); - playing = false; + playHandle->pause(false); + return; } + if (thread) + end_playback_thread(); + + { + Lock sync(this); + try + { + playHandle = & (proc::DummyPlayer::facade().start()); + start_playback_thread(); + playing = true; + } + catch (lumiera::error::State& err) + { + WARN (operate, "failed to start playback: %s" ,err.what()); + lumiera_error(); + playing = false; + } + } } void @@ -76,11 +80,13 @@ PlaybackController::pause() void PlaybackController::stop() { - Lock sync(this); - playing = false; + { + Lock sync(this); + playing = false; + playHandle = 0; + // TODO: stop player somehow? + } end_playback_thread(); - playHandle = 0; - // TODO: stop player somehow? } bool @@ -102,11 +108,15 @@ PlaybackController::start_playback_thread() void PlaybackController::end_playback_thread() { - Lock sync(this); - finish_playback_thread = true; + { + Lock sync(this); + finish_playback_thread = true; + playing = false; + } if (thread) thread->join(); thread = 0; + finish_playback_thread = false; } void diff --git a/src/gui/controller/playback-controller.hpp b/src/gui/controller/playback-controller.hpp index 9cab6d968..8b9a0916d 100644 --- a/src/gui/controller/playback-controller.hpp +++ b/src/gui/controller/playback-controller.hpp @@ -37,12 +37,12 @@ namespace gui { namespace controller { using lib::Sync; -using lib::NonrecursiveLock_NoWait; +using lib::RecursiveLock_NoWait; class PlaybackController : boost::noncopyable, - public Sync + public Sync { public: diff --git a/src/proc/play/dummy-player-service.cpp b/src/proc/play/dummy-player-service.cpp index 4ec1a87ad..ca2f0dd31 100644 --- a/src/proc/play/dummy-player-service.cpp +++ b/src/proc/play/dummy-player-service.cpp @@ -270,7 +270,7 @@ namespace proc { ProcessImpl::setRate (uint fps) { // REQUIRE (fps==0 || fps_==0 ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! - REQUIRE (fps==0 || !play_ ); + // REQUIRE (fps==0 || !play_ ); //////////////TODO: reactivate this check when we have really independent processes which can be stopped! fps_ = fps; play_ = (fps != 0); From 19c7226c9f65a6d30ffc79f8412d4c392ee4d3b8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 24 Jan 2009 22:25:50 +0100 Subject: [PATCH 18/18] Autotools fix: add dummy-player-service to lublumieraproc.so --- src/proc/Makefile.am | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index c0058adfa..ad41212ee 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -122,6 +122,18 @@ liblumiproccontrol_la_SOURCES = \ $(liblumiproccontrol_la_srcdir)/stypemanager.cpp +liblumiprocplay_la_srcdir = $(top_srcdir)/src/proc/play +noinst_LTLIBRARIES += liblumiprocplay.la + +liblumiprocplay_la_CFLAGS = $(AM_CFLAGS) -std=gnu99 -Wall -Wextra -Werror +liblumiprocplay_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra + +liblumiprocplay_la_SOURCES = \ + $(liblumiprocplay_la_srcdir)/dummy-player-service.cpp \ + $(liblumiprocplay_la_srcdir)/dummy-image-generator.cpp + + + liblumiprocmobjectsession_la_srcdir = $(top_srcdir)/src/proc/mobject/session noinst_LTLIBRARIES += liblumiprocmobjectsession.la @@ -193,6 +205,8 @@ noinst_HEADERS += \ $(liblumiproc_la_srcdir)/mobject/builderfacade.hpp \ $(liblumiproc_la_srcdir)/control/pathmanager.hpp \ $(liblumiproc_la_srcdir)/control/renderstate.hpp \ + $(liblumiproc_la_srcdir)/play/dummy-player-service.cpp \ + $(liblumiproc_la_srcdir)/play/dummy-image-generator.hpp \ $(liblumiproc_la_srcdir)/mobject/interpolator.hpp \ $(liblumiproc_la_srcdir)/mobject/parameter.hpp \ $(liblumiproc_la_srcdir)/mobject/paramprovider.hpp \ @@ -243,5 +257,6 @@ liblumieraproc_la_LIBADD = \ liblumiprocmobject.la \ liblumiprocmobjectbuilder.la \ liblumiproccontrol.la \ + liblumiprocplay.la \ liblumiprocmobjectsession.la