BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
c39aaa1
Branches
Tags
master
Blinker
src
noarch
Loveletter.cpp
clarified operator connection usage in callbacks added sound file play request to loveletter module added exit code "*#" to loveletter module
Stefan Schuermans
commited
c39aaa1
at 2011-12-23 10:59:56
Loveletter.cpp
Blame
History
Raw
/* Blinker Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <list> #include <string> #include <BlinkenLib/BlinkenFrame.h> #include <BlinkenLib/BlinkenMovie.h> #include "Directory.h" #include "File.h" #include "InStreamFile.h" #include "ListTracker.h" #include "ListTracker_impl.h" #include "Loveletter.h" #include "LoveletterMovie.h" #include "Mgrs.h" #include "Module.h" #include "NameFile.h" #include "OutStreamFile.h" #include "StreamRecv.h" #include "Time.h" #include "TimeCallee.h" namespace Blinker { /** * @brief constructor * @param[in] name module name * @param[in] mgrs managers * @param[in] dirBase base directory */ Loveletter::Loveletter(const std::string &name, Mgrs &mgrs, const Directory &dirBase): Module(name, mgrs, dirBase), m_fileSound(dirBase.getFile("sound")), m_fileOutStream(dirBase.getFile("outstream"), mgrs.m_streamMgr), m_fileHaltStream(dirBase.getFile("haltstream"), mgrs.m_streamMgr), m_movieTracker(*this, dirBase.getSubdir("movies")), m_curValid(false), m_pCurMovie(NULL), m_curFrame(0), m_curChange(false), m_halted(false), m_pOpConn(NULL), m_sendPlay(false) { // load movies m_fileHaltStream.setStreamRecv(this); m_movieTracker.init(); checkCurChanged(); // open operator connection interface m_mgrs.m_opMgr.open(m_name, this); } /// virtual destructor Loveletter::~Loveletter() { // close operator connection interface m_mgrs.m_opMgr.close(m_name); closeOpConn(); // cancel time callback request m_mgrs.m_callMgr.cancelTimeCall(this); // free all movies m_movieTracker.clear(); m_fileHaltStream.setStreamRecv(NULL); } /// check for update of configuration void Loveletter::updateConfig() { // sound name file was modified -> re-read sound name if (m_fileSound.checkModified()) m_fileSound.update(); // output stream name file was modified -> re-get output stream if (m_fileOutStream.checkModified()) { m_fileOutStream.update(); sendFrame(); } // halt stream name file was modified -> re-get halt stream if (m_fileHaltStream.checkModified()) m_fileHaltStream.update(); // movie update m_movieTracker.updateConfig(); checkCurChanged(); } /** * @brief set current frame * @param[in] stream stream name * @param[in] pFrame current frame (NULL for none) */ void Loveletter::setFrame(const std::string &stream, stBlinkenFrame *pFrame) { // this is coming from the halt stream, which will halt playing // whenever a frame is available on this halt stream // halt stream came to life -> halt playing if (pFrame && !m_halted) { m_halted = true; if (m_curValid) { // store remaining frame time m_remainTime = m_nextTime - Time::now(); if (m_remainTime < Time::zero) m_remainTime = Time::zero; } // cancel time call m_mgrs.m_callMgr.cancelTimeCall(this); } // halt stream ended -> continue playing else if (!pFrame && m_halted) { m_halted = false; if (m_curValid) { // determine time for next frame m_nextTime = Time::now() + m_remainTime; // schedule time call m_mgrs.m_callMgr.requestTimeCall(this, m_nextTime); } } (void)stream; // unused } /// callback when requested time reached void Loveletter::timeCall() { // send sound play request on operator connection if (m_sendPlay) { m_sendPlay = false; if (m_pOpConn && m_fileSound.m_valid) m_pOpConn->sendPlay(m_fileSound.m_obj.m_str); } // leave if halted if (m_halted) return; // leave if time is not yet ready to next frame if (Time::now() < m_nextTime) { // request call at time for next frame m_mgrs.m_callMgr.requestTimeCall(this, m_nextTime); return; } // go to next frame ++m_curFrame; // process new current frame procFrame(); } /** * @brief check if accepting new operator connction is possible * @param[in] name operator interface name * @return if accepting new connection is possible */ bool Loveletter::acceptNewOpConn(const std::string &name) { // accept new connection if none active return !m_pOpConn; (void)name; // unused } /** * @brief new operator connection * @param[in] name operator interface name * @param[in] pConn operator connection object * * The new connection may not yet be used for sending inside this callback. */ void Loveletter::newOpConn(const std::string &name, OpConn *pConn) { closeOpConn(); // close old connection (to be on the safe side) m_pOpConn = pConn; // remember new connection m_sendPlay = true; // schedule sending play request m_mgrs.m_callMgr.requestTimeCall(this, Time::now()); (void)name; // unused } /** * @brief key command received on operator connection * @param[in] pConn operator connection object * @param[in] key key that was pressed */ void Loveletter::opConnRecvKey(OpConn *pConn, char key) { switch (key) { // begin new movie number case '*': m_movieNumber.clear(); break; // add digit to novie number case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': m_movieNumber += key; break; // exit / play movie case '#': if (m_movieNumber.empty()) closeOpConn(); else startPlaying(); break; } (void)pConn; // unused } /** * @brief play command received on operator connection * @param[in] pConn operator connection object * @param[in] sound name of sound to play */ void Loveletter::opConnRecvPlay(OpConn *pConn, const std::string &sound) { // this events does not make sense in this direction, ignore it (void)pConn; // unused (void)sound; // unused } /** * @brief operator connection is closed * @param[in] pConn operator connection object * * The connection may not be used for sending any more in this callback. */ void Loveletter::opConnClose(OpConn *pConn) { m_pOpConn = NULL; stopPlaying(); (void)pConn; // unused } /// check if current movie changed and react void Loveletter::checkCurChanged() { // current movie changed if (m_curChange) { m_curChange = false; // go to begin of new current movie and start playing now m_curFrame = 0; m_remainTime = Time::zero; m_nextTime = Time::now(); procFrame(); } // if (m_curChange) } /// process current frame void Loveletter::procFrame() { // a movie is selected and this is loaded if (m_pCurMovie && m_pCurMovie->m_pMovie) { int frameCnt = BlinkenMovieGetFrameCnt(m_pCurMovie->m_pMovie); // movie not empty if (frameCnt > 0) { // movie finsihed -> restart if (m_curFrame >= frameCnt) m_curFrame = 0; // valid m_curValid = true; } // movie empty -> not valid else m_curValid = false; } // no movie selected or selected one not loaded -> not valid else m_curValid = false; // send new frame to stream sendFrame(); // if a frame is there if (m_curValid) { // get frame time and calculate absolute time for next frame stBlinkenFrame *pFrame = BlinkenMovieGetFrame(m_pCurMovie->m_pMovie, m_curFrame); m_remainTime.fromMs(BlinkenFrameGetDuration(pFrame)); m_nextTime += m_remainTime; // request call at time for next frame if (!m_halted) m_mgrs.m_callMgr.requestTimeCall(this, m_nextTime); } } /// send current frame to output stream void Loveletter::sendFrame() { // frame available -> send it if (m_curValid) { stBlinkenFrame *pFrame = BlinkenMovieGetFrame(m_pCurMovie->m_pMovie, m_curFrame); m_fileOutStream.setFrame(pFrame); } // no frame available -> send this information else m_fileOutStream.setFrame(NULL); } /// close current operator connection void Loveletter::closeOpConn() { if (m_pOpConn) { m_pOpConn->close(); m_pOpConn = NULL; } stopPlaying(); }; /// start playing movie (indictaed by m_movieNumber) void Loveletter::startPlaying() { // find movie and make it current MovieMap::const_iterator itMovie = m_movieMap.find(m_movieNumber); if (itMovie == m_movieMap.end()) m_pCurMovie = NULL; // not found -> no movie else m_pCurMovie = itMovie->second; // start playing movie m_curChange = true; checkCurChanged(); } /// stop playing movie void Loveletter::stopPlaying() { // forget movie number m_movieNumber.clear(); // stop playing movie m_pCurMovie = NULL; m_curChange = true; checkCurChanged(); } } // namespace Blinker