BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
1877dbc
Branches
Tags
master
Blinker
src
common
SyncReceiver_impl.h
implement UDP synchronization receivers
Stefan Schuermans
commited
1877dbc
at 2014-01-03 16:19:05
SyncReceiver_impl.h
Blame
History
Raw
/* Blinker Copyright 2011-2014 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #ifndef BLINKER_SYNCRECEIVER_IMPL_H #define BLINKER_SYNCRECEIVER_IMPL_H #include <stdint.h> #include <string> #include <string.h> #include "Directory.h" #include "File.h" #include "IoCallee.h" #include "Mgrs.h" #include "Module.h" #include "NetHost.h" #include "OutSyncFile.h" #include "Protocol.h" #include "ProtocolFile.h" #include "SettingFile.h" #include "SyncRecv.h" #include "SyncReceiver.h" namespace Blinker { /** * @brief constructor * @param[in] name module name * @param[in] mgrs managers * @param[in] dirBase base directory */ template<typename ADDR, typename SOCK> SyncReceiver<ADDR, SOCK>::SyncReceiver(const std::string &name, Mgrs &mgrs, const Directory &dirBase): Module(name, mgrs, dirBase), m_fileOutSync(dirBase.getFile("outsync"), mgrs.m_syncMgr), m_fileBind(dirBase.getFile("bind")), m_fileSrc(dirBase.getFile("source")), m_pSock(NULL) { // read source address m_fileSrc.update(); // create and bind socket createSock(); } /// virtual destructor template<typename ADDR, typename SOCK> SyncReceiver<ADDR, SOCK>::~SyncReceiver() { // destroy socket destroySock(); } /// check for update of configuration template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::updateConfig() { // output sync stream name file was modified -> re-get output sync stream if (m_fileOutSync.checkModified()) m_fileOutSync.update(); // bind address file was modified -> re-create socket if (m_fileBind.checkModified()) { destroySock(); createSock(); } // source address file was modified -> re-read source address if (m_fileSrc.checkModified()) m_fileSrc.update(); } /** * @brief callback when I/O object is readable * @param[in] io I/O object that is readable */ template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::ioReadCall(Io *io) { // reception on socket if (io == m_pSock) receiveFromSock(); } /** * @brief callback when I/O object is writable * @param[in] io I/O object that is writable */ template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::ioWriteCall(Io *io) { (void)io; // unused } /// create socket and bind it template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::createSock() { // create socket if (!m_pSock) { m_pSock = new SOCK(); if (!m_pSock) return; } // get bind address from bind address setting file m_fileBind.update(); if (!m_fileBind.m_valid) { delete m_pSock; m_pSock = NULL; return; } // bind socket if (!m_pSock->bind(m_fileBind.m_obj)) { delete m_pSock; m_pSock = NULL; return; } // request callback on recepetion m_mgrs.m_callMgr.requestIoReadCall(this, m_pSock); } /// destroy socket template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::destroySock() { // cancel callback request m_mgrs.m_callMgr.cancelIoReadCall(this, m_pSock); // destroy socket if (m_pSock) { delete m_pSock; m_pSock = NULL; } } /// receive data from socket template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::receiveFromSock() { std::string data; ADDR addr; // make sure socket exists if (!m_pSock) return; // receive (leave if no reception) if (!m_pSock->recv(data, addr)) return; // check source address (if configured) if (m_fileSrc.m_valid && addr != m_fileSrc.m_obj) return; // mismatch // process received synchronization information procInfo(data); } /** * @brief process synchronization information * @param[in] data received synchronization data */ template<typename ADDR, typename SOCK> void SyncReceiver<ADDR, SOCK>::procInfo(const std::string &data) { /// Po.W.E.R. (stage play by BBM) synchronization protocol struct PoSyPacket { char magic[4]; ///< fixed magic, always "PoSy" uint32_t flags; ///< flags, see PosSyFlags below char name[64]; ///< name of current piece in playlist uint32_t pos_ms; ///< position within current piece in milliseconds }; /// flags for PoSyPacket enum PoSyFlags { PoSyPause = 0x00000001, ///< pause mode active }; PoSyPacket packet; SyncRecv::Info info; // parse frame, leave if invalid if (data.size() < sizeof(packet)) return; memcpy(&packet, data.c_str(), sizeof(packet)); if (memcmp(packet.magic, "PoSy", sizeof(packet.magic)) != 0) return; info.pause = (Net2Host32(packet.flags) & PoSyPause) != 0; info.name = packet.name; info.pos_ms = Net2Host32(packet.pos_ms); // pass on sync information m_fileOutSync.sendInfo(info); } } // namespace Blinker #endif // #ifndef BLINKER_SYNCRECEIVER_IMPL_H