implement PlayOut subsystem and draft OutputDirector

This commit is contained in:
Fischlurch 2011-06-14 05:41:02 +02:00
parent 971dea6f6a
commit 1b0cb56dcc
13 changed files with 270 additions and 73 deletions

View file

@ -200,7 +200,7 @@ namespace backend {
/** Synchronisation barrier. In the function executing in this thread
* needs to be a corresponding Thread::sync() call. Blocking until
* needs to be a corresponding Thread::syncPoint() call. Blocking until
* both the caller and the thread have reached the barrier.
*/
void

View file

@ -156,7 +156,7 @@ namespace gui {
if (facade)
{
WARN (guifacade, "GUI subsystem terminates, but GuiFacade isn't properly closed. "
"Closing it forcedly; this indicates broken startup logic and should be fixed.");
"Closing it forcedly; this indicates broken startup logic and should be fixed.");
try { facade.reset (0); }
catch(...) { WARN_IF (lumiera_error_peek(), guifacade, "Ignoring error: %s", lumiera_error()); }
lumiera_error(); // clear any remaining error state...

View file

@ -104,9 +104,12 @@ namespace lumiera {
/** initiate termination of this subsystem.
* may be called repeatedly any time...
* @warning must not block nor throw. */
virtual void triggerShutdown () throw() =0;
* This trigger may be called repeatedly any time...
* When the subsystem actually has terminated,
* the SigTerm passed to #start must be invoked.
* @note called within a locked context (barrier)
* @warning must not block nor throw. */
virtual void triggerShutdown () throw() =0;
const std::vector<Subsys*>
@ -114,7 +117,7 @@ namespace lumiera {
private:
/** weather this subsystem is actually operational.
/** whether this subsystem is actually operational.
* When returning \c false here, the application may
* terminate at any point without further notice
* Note further, that a subsystem must not be in

View file

@ -173,7 +173,7 @@ namespace lumiera {
if (!and_all (susy->getPrerequisites(), isRunning() ))
{
susy->triggerShutdown();
throw error::Logic("Unable to start all prerequisites of Subsystem "+string(*susy));
throw error::State("Unable to start all prerequisites of Subsystem "+string(*susy));
} }
void

View file

@ -58,11 +58,10 @@ namespace lib {
/**
* Result value and status of some operation.
* It can be created for passing a result produced
* by the operation, or the failure to do so. The value
* can be retrieved by implicit or explicit conversion.
* @throws on any attempt to access the value in case of failure
* Optional Result value or status of some operation.
* It can be created for passing a result produced by the operation, or the
* failure to do so. The value can be retrieved by implicit or explicit conversion.
* @throw error::State on any attempt to access the value in case of failure
* @warning this class has a lot of implicit conversions;
* care should be taken when defining functions
* to take Result instances as parameter....

View file

@ -67,6 +67,7 @@ namespace control {
* It is returned when invoking a HandlingPattern
* and can be used to check for success and/or re-throw
* any Exception encountered during the command execution.
* @todo couldn't that be replaced by a lib::Result<void> instance??
*/
class ExecResult
: public lib::BoolCheckable<ExecResult>

View file

@ -23,6 +23,7 @@
#include "proc/facade.hpp"
#include "lib/singleton.hpp"
#include "proc/play/output-director.hpp"
#include <string>
@ -77,7 +78,7 @@ namespace proc {
bool
shouldStart (lumiera::Option&)
{
TODO ("determine, if an existing Session schould be loaded");
TODO ("determine, if an existing Session should be loaded");
return false;
}
@ -127,22 +128,24 @@ namespace proc {
bool
start (lumiera::Option&, Subsys::SigTerm termination)
{
UNIMPLEMENTED ("bring up and configure the output connections and the player");
return false;
this->completedSignal_ = termination;
return play::OutputDirector::instance().connectUp();
}
SigTerm completedSignal_;
void
triggerShutdown () throw()
{
UNIMPLEMENTED ("initiate playback/render halt and disconnect output");
play::OutputDirector::instance().triggerDisconnect (completedSignal_);
}
bool
checkRunningState () throw()
{
//Lock guard (*this);
TODO ("implement detecting running state");
return false;
return play::OutputDirector::instance().isOperational();
}
};

View file

@ -31,7 +31,7 @@
** here; any implementation is delegated to the relevant session facilities.
**
** The idea of a LifecycleAdvisor is inspired by GUI frameworks, especially
** Spring RichClient. Typically, such frameworks provides a means for flexible
** Spring RichClient. Typically, such frameworks provide a means for flexible
** configuration of the application lifecycle. Configurability isn't the primary
** goal here, as there is only one Lumiera application and the session lifecycle
** can be considered fixed, with the exception of some extension points, which are
@ -64,7 +64,7 @@ namespace session {
/**
* Skeleton operations conducting the session lifecycle sequences.
* Skeleton of operations conducting the session lifecycle sequences.
* Any details of the operations are delegated to the current session
* and associated services.
* @warning this object is assumed to be used as a single instance

View file

@ -67,7 +67,7 @@ namespace session {
SessionImplAPI*
SessManagerImpl::operator-> () throw()
{
if (!pImpl_)
if (!pSess_)
try
{ // create empty default configured session
this->reset();
@ -80,7 +80,7 @@ namespace session {
}
return pImpl_.get();
return pSess_.get();
}
@ -201,8 +201,8 @@ namespace session {
* \link #operator-> access \endlink to the session object.
*/
SessManagerImpl::SessManagerImpl () throw()
: pImpl_ (0)
, lifecycle_(new SessionLifecycleDetails(pImpl_))
: pSess_ (0)
, lifecycle_(new SessionLifecycleDetails(pSess_))
{
Session::initFlag = true; //////////////////////////////////////// TICKET #518 instead of this hack, implement basic-init of the session manager for real
}
@ -219,7 +219,7 @@ namespace session {
bool
SessManagerImpl::isUp ()
{
return bool(pImpl_); ///////////////////// TICKET #702 possible race, because this gets true way before the interface is up
return bool(pSess_); ///////////////////// TICKET #702 possible race, because this gets true way before the interface is up
}
/** @note no transactional behaviour. may succeed partially.
@ -229,7 +229,7 @@ namespace session {
SessManagerImpl::clear ()
{
Lock sync(this);
pImpl_->clear();
pSess_->clear();
}
@ -242,7 +242,7 @@ namespace session {
{
Lock sync(this);
lifecycle_->shutDown();
pImpl_.reset();
pSess_.reset();
}

View file

@ -42,7 +42,7 @@ namespace session {
: public SessManager
, public lib::Sync<>
{
scoped_ptr<SessionImplAPI> pImpl_;
scoped_ptr<SessionImplAPI> pSess_;
scoped_ptr<LifecycleAdvisor> lifecycle_;
SessManagerImpl() throw();

View file

@ -0,0 +1,135 @@
/*
OutputDirector - handling all the real external output connections
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
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/play-service.hpp"
#include "proc/play/output-manager.hpp"
#include "proc/play/output-director.hpp"
#include "backend/thread-wrapper.hpp"
using backend::Thread;
namespace proc {
namespace play {
namespace { // hidden local details of the service implementation....
} // (End) hidden service impl details
/** storage for the single application wide OutputDirector instance */
lib::Singleton<OutputDirector> OutputDirector::instance;
/** bring up the framework for handling input/output connections.
* Creating this object happens on first access and shouldn't be
* confused with actually booting up / shutting down this subsystem.
* Rather, the purpose of the OutputDirector is actively to conduct
* the Lifecycle of booting, connecting, operating, disconnecting.
*/
OutputDirector::OutputDirector()
{ }
OutputDirector::~OutputDirector() { }
/** connect and bring up the external input/output connections,
* handlers and interface services and the render/playback service.
* @return true if the output subsystem can be considered operational
*
* @todo WIP-WIP-WIP 6/2011
*/
bool
OutputDirector::connectUp()
{
Lock sync(this);
player_.reset (new PlayService);
return this->isOperational();
}
bool
OutputDirector::isOperational() const
{
return bool(player_); ////////////TODO more to check here....
}
/** initiate shutdown of all ongoing render/playback processes
* and closing of all external input/output interfaces.
* Works as an asynchronous operation; the given callback signal
* will be invoked when the shutdown is complete.
* @note starting a new thread, which might fail.
* When this happens, the raised exception will cause
* immediate unconditional termination of the application.
*/
void
OutputDirector::triggerDisconnect (SigTerm completedSignal) throw()
{
Thread ("Output shutdown supervisor", bind (&OutputDirector::bringDown, this, completedSignal));
}
/** @internal actually bring down any calculation processes
* and finally disconnect any external input/output interfaces.
* This shutdown and cleanup operation is executed in a separate
* "Output shutdown supervisor" thread and has the liability to
* bring down the relevant facilities within a certain timespan.
* When done, the last operation within this thread will be to
* invoke the callback signal given as parameter.
* @note locks the OutputDirector
*/
void
OutputDirector::bringDown (SigTerm completedSignal)
{
Lock sync(this);
string problemLog;
try
{
TODO ("actually bring down the output generation");
player_.reset(0);
completedSignal(0);
}
catch (lumiera::Error& problem)
{
problemLog = problem.what();
lumiera_error(); // reset error state
completedSignal (&problemLog);
}
catch (...)
{
problemLog = "Unknown error while disconnecting output. "
"Lumiera error flag is = "+string(lumiera_error());
completedSignal (&problemLog);
}
}
}} // namespace proc::play

View file

@ -0,0 +1,100 @@
/*
OUTPUT-DIRECTOR.hpp - handling all the real external output connections
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
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 output-director.hpp
** A global service to coordinate and handle all external output activities.
** The OutputDirector is an application internal singleton service for
** coordinating and controlling all actual input/output- and rendering
** capabilities, exposing distinct lifecycle functions to connect, bring
** up and shut down what can be considered the "Player/Output" subsystem.
**
** @see output-manager-test.cpp ////TODO
*/
#ifndef PROC_PLAY_OUTPUT_DIRECTOR_H
#define PROC_PLAY_OUTPUT_DIRECTOR_H
#include "lib/error.hpp"
#include "lib/singleton.hpp"
#include "proc/play/output-manager.hpp"
#include "common/subsys.hpp"
#include "lib/sync.hpp"
#include <boost/noncopyable.hpp>
//#include <string>
//#include <vector>
//#include <tr1/memory>
#include <boost/scoped_ptr.hpp>
namespace proc {
namespace play {
//using std::string;
//using std::vector;
//using std::tr1::shared_ptr;
using boost::scoped_ptr;
class PlayService;
//typedef lib::ScopedPtrVect<DisplayerSlot> DisplayerTab;
/******************************************************
* Management of external Output connections.
*
* @todo write Type comment
*/
class OutputDirector
: boost::noncopyable
, public lib::Sync<>
{
typedef lumiera::Subsys::SigTerm SigTerm;
scoped_ptr<PlayService> player_;
public:
static lib::Singleton<OutputDirector> instance;
bool connectUp() ;
void triggerDisconnect(SigTerm) throw();
bool isOperational() const;
private:
OutputDirector() ;
~OutputDirector() ;
friend class lib::singleton::StaticCreate<OutputDirector>;
void bringDown (SigTerm completedSignal);
};
}} // namespace proc::play
#endif

View file

@ -1,44 +0,0 @@
/*
OutputManager - handling all the real external output connections
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
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/output-manager.hpp"
namespace proc {
namespace play {
namespace { // hidden local details of the service implementation....
} // (End) hidden service impl details
OutputSlot::~OutputSlot() { }
}} // namespace proc::play