diff options
Diffstat (limited to 'src/player/Publisher.cpp')
-rw-r--r-- | src/player/Publisher.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/src/player/Publisher.cpp b/src/player/Publisher.cpp new file mode 100644 index 0000000..01bbea3 --- /dev/null +++ b/src/player/Publisher.cpp @@ -0,0 +1,248 @@ +// +// libavg - Media Playback Engine. +// Copyright (C) 2003-2014 Ulrich von Zadow +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Current versions can be found at www.libavg.de +// + +#include "Publisher.h" + +#include "SubscriberInfo.h" +#include "PublisherDefinitionRegistry.h" +#include "Player.h" + +#include "../base/Exception.h" +#include "../base/StringHelper.h" + +using namespace std; + +namespace avg { + +int Publisher::s_LastSubscriberID = 0; + +Publisher::Publisher() +{ + m_pPublisherDef = PublisherDefinition::create(""); +} + +Publisher::Publisher(const string& sTypeName) +{ + m_pPublisherDef = PublisherDefinitionRegistry::get()->getDefinition(sTypeName); + vector<MessageID> messageIDs = m_pPublisherDef->getMessageIDs(); + for (unsigned i=0; i<messageIDs.size(); ++i) { + m_SignalMap[messageIDs[i]] = list<SubscriberInfoPtr>(); + } +} + +Publisher::~Publisher() +{ +} + +int Publisher::subscribe(MessageID messageID, const py::object& callable) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + int subscriberID = s_LastSubscriberID; + s_LastSubscriberID++; +// cerr << this << " subscribe " << messageID << ", " << subscriberID << endl; + subscribers.push_front(SubscriberInfoPtr(new SubscriberInfo(subscriberID, callable))); + return subscriberID; +} + +void Publisher::unsubscribe(MessageID messageID, int subscriberID) +{ +// cerr << this << " unsubscribe " << messageID << ", " << subscriberID << endl; +// cerr << " "; +// dumpSubscribers(messageID); + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + SubscriberInfoList::iterator it; + for (it = subscribers.begin(); it != subscribers.end(); it++) { + if ((*it)->getID() == subscriberID) { + unsubscribeIterator(messageID, it); + return; + } + } +// cerr << " End of unsubscribe: "; +// dumpSubscribers(messageID); + throwSubscriberNotFound(messageID, subscriberID); +} + +void Publisher::unsubscribe1(int subscriberID) +{ + SignalMap::iterator it; + for (it = m_SignalMap.begin(); it != m_SignalMap.end(); ++it) { + SubscriberInfoList& subscribers = it->second; + SubscriberInfoList::iterator it2; + for (it2 = subscribers.begin(); it2 != subscribers.end(); it2++) { + if ((*it2)->getID() == subscriberID) { + MessageID messageID = it->first; + unsubscribeIterator(messageID, it2); + return; + } + } + } + throw Exception(AVG_ERR_INVALID_ARGS, + "Subscriber with ID "+toString(subscriberID)+" not found."); +} + +void Publisher::unsubscribeCallable(MessageID messageID, const py::object& callable) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + SubscriberInfoList::iterator it; + for (it = subscribers.begin(); it != subscribers.end(); it++) { + if ((*it)->isCallable(callable)) { + unsubscribeIterator(messageID, it); + return; + } + } + throwSubscriberNotFound(messageID, -1); +} + +int Publisher::getNumSubscribers(MessageID messageID) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + return subscribers.size(); +} + +bool Publisher::isSubscribed(MessageID messageID, int subscriberID) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + SubscriberInfoList::iterator it; + for (it = subscribers.begin(); it != subscribers.end(); it++) { + if ((*it)->getID() == subscriberID) { + return true; + } + } + return false; +} + +bool Publisher::isSubscribedCallable(MessageID messageID, const py::object& callable) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + SubscriberInfoList::iterator it; + for (it = subscribers.begin(); it != subscribers.end(); it++) { + if ((*it)->isCallable(callable)) { + return true; + } + } + return false; +} + +void Publisher::publish(MessageID messageID) +{ + if (m_SignalMap.find(messageID) != m_SignalMap.end()) { + throw Exception(AVG_ERR_INVALID_ARGS, "Signal with ID "+toString(messageID)+ + "already registered."); + } + m_SignalMap[messageID] = SubscriberInfoList(); +} + +void Publisher::removeSubscribers() +{ + SignalMap::iterator it; + for (it = m_SignalMap.begin(); it != m_SignalMap.end(); ++it) { + it->second = SubscriberInfoList(); + } +} + +void Publisher::notifySubscribers(MessageID messageID) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + if (!subscribers.empty()) { + py::list args; + notifySubscribersPy(messageID, args); + } +} + +void Publisher::notifySubscribers(const string& sMsgName) +{ + MessageID messageID = m_pPublisherDef->getMessageID(sMsgName); + notifySubscribers(messageID); +} + +void Publisher::notifySubscribersPy(MessageID messageID, const py::list& args) +{ +// cerr << this << " notifySubscribers " << messageID << endl; +// cerr << " "; +// dumpSubscribers(messageID); + AVG_ASSERT(!(Player::get()->isTraversingTree())); + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + WeakSubscriberInfoList subRefs; + for (SubscriberInfoList::iterator it = subscribers.begin(); it != subscribers.end(); + ++it) + { + subRefs.push_back(*it); + } + WeakSubscriberInfoList::iterator it; + for (it = subRefs.begin(); it != subRefs.end(); ++it) { +// cerr << " next" << endl; + if (!(*it).expired()) { + SubscriberInfoPtr pSub = (*it).lock(); + if (pSub->hasExpired()) { + // Python subscriber doesn't exist anymore -> auto-unsubscribe. + unsubscribe(messageID, pSub->getID()); + } else { +// cerr << " invoke: " << (*it)->getID() << endl; + pSub->invoke(args); + } + } + } +// cerr << " end notify" << endl; +} + +MessageID Publisher::genMessageID() +{ + return PublisherDefinitionRegistry::get()->genMessageID(); +} + +void Publisher::unsubscribeIterator(MessageID messageID, SubscriberInfoList::iterator it) +{ + m_SignalMap[messageID].erase(it); +} + + +Publisher::SubscriberInfoList& Publisher::safeFindSubscribers(MessageID messageID) +{ + if (m_SignalMap.find(messageID) == m_SignalMap.end()) { + throw Exception(AVG_ERR_INVALID_ARGS, "No signal with ID "+toString(messageID)); + } + SubscriberInfoList& subscribers = m_SignalMap[messageID]; + return subscribers; +} + +void Publisher::throwSubscriberNotFound(MessageID messageID, int subscriberID) +{ + if (subscriberID == -1) { + throw Exception(AVG_ERR_INVALID_ARGS, "Signal with ID "+toString(messageID)+ + " doesn't have a subscriber with the given callable."); + } else { + throw Exception(AVG_ERR_INVALID_ARGS, "Signal with ID "+toString(messageID)+ + " doesn't have a subscriber with ID "+toString(subscriberID)); + } +} + +void Publisher::dumpSubscribers(MessageID messageID) +{ + SubscriberInfoList& subscribers = safeFindSubscribers(messageID); + SubscriberInfoList::iterator it; + for (it = subscribers.begin(); it != subscribers.end(); it++) { + cerr << (*it)->getID() << " "; + } + cerr << endl; +} + + +} |