1a0795c6fSMarcus Overhagen // NodeGroup.cpp 2a0795c6fSMarcus Overhagen 3a0795c6fSMarcus Overhagen #include "NodeGroup.h" 4a0795c6fSMarcus Overhagen //#include "NodeGroup_transport_thread.h" 5a0795c6fSMarcus Overhagen 6a0795c6fSMarcus Overhagen #include "NodeManager.h" 7a0795c6fSMarcus Overhagen #include "NodeRef.h" 8a0795c6fSMarcus Overhagen 9a0795c6fSMarcus Overhagen #include <MediaRoster.h> 10a0795c6fSMarcus Overhagen #include <OS.h> 11a0795c6fSMarcus Overhagen #include <TimeSource.h> 12a0795c6fSMarcus Overhagen 13a0795c6fSMarcus Overhagen #include <algorithm> 14a0795c6fSMarcus Overhagen #include <functional> 15a0795c6fSMarcus Overhagen 16a0795c6fSMarcus Overhagen #include "array_delete.h" 17a0795c6fSMarcus Overhagen #include "BasicThread.h" 18a0795c6fSMarcus Overhagen #include "node_manager_impl.h" 19a0795c6fSMarcus Overhagen #include "functional_tools.h" 20a0795c6fSMarcus Overhagen 21*23e67806SIthamar R. Adema using namespace std; 22*23e67806SIthamar R. Adema 23a0795c6fSMarcus Overhagen __USE_CORTEX_NAMESPACE 24a0795c6fSMarcus Overhagen #define D_METHOD(x) //PRINT (x) 25a0795c6fSMarcus Overhagen #define D_ROSTER(x) //PRINT (x) 26a0795c6fSMarcus Overhagen #define D_LOCK(x) //PRINT (x) 27a0795c6fSMarcus Overhagen 28a0795c6fSMarcus Overhagen 29a0795c6fSMarcus Overhagen 30a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 31a0795c6fSMarcus Overhagen // *** ctor/dtor 32a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 33a0795c6fSMarcus Overhagen 34a0795c6fSMarcus Overhagen // free the group, including all nodes within it 35a0795c6fSMarcus Overhagen // (this call will result in the eventual deletion of the object.) 36a0795c6fSMarcus Overhagen // returns B_OK on success; B_NOT_ALLOWED if release() has 37a0795c6fSMarcus Overhagen // already been called; other error codes if the Media Roster 38a0795c6fSMarcus Overhagen // call fails. 39a0795c6fSMarcus Overhagen // * THE MANAGER MUST BE LOCKED 40a0795c6fSMarcus Overhagen 41a0795c6fSMarcus Overhagen status_t NodeGroup::release() { 42a0795c6fSMarcus Overhagen 43a0795c6fSMarcus Overhagen D_METHOD(( 44a0795c6fSMarcus Overhagen "NodeGroup::release()\n")); 45a0795c6fSMarcus Overhagen 46a0795c6fSMarcus Overhagen if(isReleased()) 47a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 48a0795c6fSMarcus Overhagen 49a0795c6fSMarcus Overhagen // clean up 50a0795c6fSMarcus Overhagen lock(); 51a0795c6fSMarcus Overhagen 52a0795c6fSMarcus Overhagen // halt all nodes 53a0795c6fSMarcus Overhagen _stop(); 54a0795c6fSMarcus Overhagen 55a0795c6fSMarcus Overhagen // remove & release all nodes 56a0795c6fSMarcus Overhagen // +++++ causes triply-nested lock: eww! 57a0795c6fSMarcus Overhagen while(m_nodes.size()) { 58a0795c6fSMarcus Overhagen NodeRef* last = m_nodes.back(); 59a0795c6fSMarcus Overhagen removeNode(m_nodes.size()-1); 60a0795c6fSMarcus Overhagen last->release(); 61a0795c6fSMarcus Overhagen } 62a0795c6fSMarcus Overhagen 63a0795c6fSMarcus Overhagen unlock(); 64a0795c6fSMarcus Overhagen 65a0795c6fSMarcus Overhagen // [e.moon 7nov99] 66a0795c6fSMarcus Overhagen // removing the released group is now NodeManager's responsibility 67a0795c6fSMarcus Overhagen // 68a0795c6fSMarcus Overhagen // remove from NodeManager 69a0795c6fSMarcus Overhagen if(!m_manager->lock()) { 70a0795c6fSMarcus Overhagen ASSERT(!"* m_manager->lock() failed.\n"); 71a0795c6fSMarcus Overhagen } 72a0795c6fSMarcus Overhagen m_manager->_removeGroup(this); 73a0795c6fSMarcus Overhagen m_manager->unlock(); 74a0795c6fSMarcus Overhagen 75a0795c6fSMarcus Overhagen // hand off to IObservable 76a0795c6fSMarcus Overhagen return _inherited::release(); 77a0795c6fSMarcus Overhagen } 78a0795c6fSMarcus Overhagen 79a0795c6fSMarcus Overhagen // call release() rather than deleting NodeGroup objects 80a0795c6fSMarcus Overhagen NodeGroup::~NodeGroup() { 81a0795c6fSMarcus Overhagen 82a0795c6fSMarcus Overhagen Autolock _l(this); 83a0795c6fSMarcus Overhagen D_METHOD(( 84a0795c6fSMarcus Overhagen "~NodeGroup()\n")); 85a0795c6fSMarcus Overhagen 86a0795c6fSMarcus Overhagen ASSERT(!m_nodes.size()); 87a0795c6fSMarcus Overhagen 88a0795c6fSMarcus Overhagen if(m_timeSourceObj) { 89a0795c6fSMarcus Overhagen m_timeSourceObj->Release(); 90a0795c6fSMarcus Overhagen m_timeSourceObj = 0; 91a0795c6fSMarcus Overhagen } 92a0795c6fSMarcus Overhagen } 93a0795c6fSMarcus Overhagen 94a0795c6fSMarcus Overhagen 95a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 96a0795c6fSMarcus Overhagen // *** accessors 97a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 98a0795c6fSMarcus Overhagen 99a0795c6fSMarcus Overhagen // [e.moon 13oct99] moved to header 100a0795c6fSMarcus Overhagen //inline uint32 NodeGroup::id() const { return m_id; } 101a0795c6fSMarcus Overhagen 102a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 103a0795c6fSMarcus Overhagen // *** operations 104a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 105a0795c6fSMarcus Overhagen 106a0795c6fSMarcus Overhagen // name access 107a0795c6fSMarcus Overhagen const char* NodeGroup::name() const { 108a0795c6fSMarcus Overhagen Autolock _l(this); 109a0795c6fSMarcus Overhagen return m_name.String(); 110a0795c6fSMarcus Overhagen } 111a0795c6fSMarcus Overhagen 112a0795c6fSMarcus Overhagen status_t NodeGroup::setName(const char* name) { 113a0795c6fSMarcus Overhagen Autolock _l(this); 114a0795c6fSMarcus Overhagen m_name = name; 115a0795c6fSMarcus Overhagen return B_OK; 116a0795c6fSMarcus Overhagen } 117a0795c6fSMarcus Overhagen 118a0795c6fSMarcus Overhagen // content access 119a0795c6fSMarcus Overhagen uint32 NodeGroup::countNodes() const { 120a0795c6fSMarcus Overhagen Autolock _l(this); 121a0795c6fSMarcus Overhagen return m_nodes.size(); 122a0795c6fSMarcus Overhagen } 123a0795c6fSMarcus Overhagen 124a0795c6fSMarcus Overhagen NodeRef* NodeGroup::nodeAt( 125a0795c6fSMarcus Overhagen uint32 index) const { 126a0795c6fSMarcus Overhagen Autolock _l(this); 127a0795c6fSMarcus Overhagen return (index < m_nodes.size()) ? 128a0795c6fSMarcus Overhagen m_nodes[index] : 129a0795c6fSMarcus Overhagen 0; 130a0795c6fSMarcus Overhagen } 131a0795c6fSMarcus Overhagen 132a0795c6fSMarcus Overhagen // add/remove nodes: 133a0795c6fSMarcus Overhagen // - you may only add a node with no current group. 134a0795c6fSMarcus Overhagen // - nodes added during playback will be started; 135a0795c6fSMarcus Overhagen // nodes removed during playback will be stopped (unless 136a0795c6fSMarcus Overhagen // the NO_START_STOP transport restriction flag is set 137a0795c6fSMarcus Overhagen // for a given node.) 138a0795c6fSMarcus Overhagen 139a0795c6fSMarcus Overhagen status_t NodeGroup::addNode( 140a0795c6fSMarcus Overhagen NodeRef* node) { 141a0795c6fSMarcus Overhagen 142a0795c6fSMarcus Overhagen D_METHOD(( 143a0795c6fSMarcus Overhagen "NodeGroup::addNode()\n")); 144a0795c6fSMarcus Overhagen 145a0795c6fSMarcus Overhagen // lock the manager first; if the node has no current group, 146a0795c6fSMarcus Overhagen // this locks the node. 147a0795c6fSMarcus Overhagen m_manager->lock(); 148a0795c6fSMarcus Overhagen 149a0795c6fSMarcus Overhagen Autolock _l(this); 150a0795c6fSMarcus Overhagen 151a0795c6fSMarcus Overhagen // precondition: GROUP_LOCKED not set 152a0795c6fSMarcus Overhagen if(m_flags & GROUP_LOCKED) 153a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 154a0795c6fSMarcus Overhagen 155a0795c6fSMarcus Overhagen // precondition: no current group 156a0795c6fSMarcus Overhagen if(node->m_group) { 157a0795c6fSMarcus Overhagen // [e.moon 28sep99] whoops, forgot one 158a0795c6fSMarcus Overhagen PRINT(( 159a0795c6fSMarcus Overhagen "!!! node already in group '%s'\n", node->m_group->name())); 160a0795c6fSMarcus Overhagen 161a0795c6fSMarcus Overhagen m_manager->unlock(); 162a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 163a0795c6fSMarcus Overhagen } 164a0795c6fSMarcus Overhagen 165a0795c6fSMarcus Overhagen // add it 166a0795c6fSMarcus Overhagen m_nodes.push_back(node); 167a0795c6fSMarcus Overhagen node->_setGroup(this); 168a0795c6fSMarcus Overhagen 169a0795c6fSMarcus Overhagen // release the manager 170a0795c6fSMarcus Overhagen m_manager->unlock(); 171a0795c6fSMarcus Overhagen 172a0795c6fSMarcus Overhagen // first node? the transport is now ready to start 173a0795c6fSMarcus Overhagen if(m_nodes.size() == 1) { 174a0795c6fSMarcus Overhagen _changeState(TRANSPORT_INVALID, TRANSPORT_STOPPED); 175a0795c6fSMarcus Overhagen } 176a0795c6fSMarcus Overhagen // 177a0795c6fSMarcus Overhagen // if(m_syncNode == media_node::null) { 178a0795c6fSMarcus Overhagen // // assign as sync node 179a0795c6fSMarcus Overhagen // setSyncNode(node->node()); 180a0795c6fSMarcus Overhagen // } 181a0795c6fSMarcus Overhagen // 182a0795c6fSMarcus Overhagen // initialize the new node 183a0795c6fSMarcus Overhagen status_t err = node->_initTransportState(); 184a0795c6fSMarcus Overhagen if(err < B_OK) 185a0795c6fSMarcus Overhagen return err; 186a0795c6fSMarcus Overhagen 187a0795c6fSMarcus Overhagen // set time source 188a0795c6fSMarcus Overhagen node->_setTimeSource(m_timeSource.node); 189a0795c6fSMarcus Overhagen 190a0795c6fSMarcus Overhagen // set run mode 191a0795c6fSMarcus Overhagen node->_setRunMode(m_runMode); 192a0795c6fSMarcus Overhagen 193a0795c6fSMarcus Overhagen // add to cycle set if need be 194a0795c6fSMarcus Overhagen // +++++ should I call _cycleAddRef() instead? 195a0795c6fSMarcus Overhagen if(node->m_cycle) 196a0795c6fSMarcus Overhagen _refCycleChanged(node); 197a0795c6fSMarcus Overhagen 198a0795c6fSMarcus Overhagen if(m_transportState == TRANSPORT_RUNNING) { 199a0795c6fSMarcus Overhagen // +++++ start if necessary! 200a0795c6fSMarcus Overhagen } 201a0795c6fSMarcus Overhagen // +++++ not started if TRANSPORT_ROLLING: is that proper? [e.moon 11oct99] 202a0795c6fSMarcus Overhagen 203a0795c6fSMarcus Overhagen // send notification 204a0795c6fSMarcus Overhagen if(!LockLooper()) { 205a0795c6fSMarcus Overhagen ASSERT(!"LockLooper() failed."); 206a0795c6fSMarcus Overhagen } 207a0795c6fSMarcus Overhagen BMessage m(M_NODE_ADDED); 208a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 209a0795c6fSMarcus Overhagen m.AddInt32("nodeID", node->id()); 210a0795c6fSMarcus Overhagen notify(&m); 211a0795c6fSMarcus Overhagen UnlockLooper(); 212a0795c6fSMarcus Overhagen 213a0795c6fSMarcus Overhagen // success 214a0795c6fSMarcus Overhagen return B_OK; 215a0795c6fSMarcus Overhagen } 216a0795c6fSMarcus Overhagen 217a0795c6fSMarcus Overhagen 218a0795c6fSMarcus Overhagen status_t NodeGroup::removeNode( 219a0795c6fSMarcus Overhagen NodeRef* node) { 220a0795c6fSMarcus Overhagen 221a0795c6fSMarcus Overhagen D_METHOD(( 222a0795c6fSMarcus Overhagen "NodeGroup::removeNode()\n")); 223a0795c6fSMarcus Overhagen 224a0795c6fSMarcus Overhagen // lock the manager first; once the node is ungrouped, 225a0795c6fSMarcus Overhagen // the manager lock applies to it 226a0795c6fSMarcus Overhagen m_manager->lock(); 227a0795c6fSMarcus Overhagen 228a0795c6fSMarcus Overhagen Autolock _l(this); 229a0795c6fSMarcus Overhagen 230a0795c6fSMarcus Overhagen // precondition: this must be the node's group 231a0795c6fSMarcus Overhagen if(node->m_group != this) { 232a0795c6fSMarcus Overhagen // [e.moon 28sep99] whoops, forgot one 233a0795c6fSMarcus Overhagen PRINT(( 234a0795c6fSMarcus Overhagen "!!! node not in group '%s'\n", node->m_group->name())); 235a0795c6fSMarcus Overhagen 236a0795c6fSMarcus Overhagen m_manager->unlock(); 237a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 238a0795c6fSMarcus Overhagen } 239a0795c6fSMarcus Overhagen 240a0795c6fSMarcus Overhagen // remove from the cycle set 241a0795c6fSMarcus Overhagen if(node->m_cycle) 242a0795c6fSMarcus Overhagen _cycleRemoveRef(node); 243a0795c6fSMarcus Overhagen 244a0795c6fSMarcus Overhagen // remove it 245a0795c6fSMarcus Overhagen ASSERT(m_nodes.size()); 246a0795c6fSMarcus Overhagen remove( 247a0795c6fSMarcus Overhagen m_nodes.begin(), 248a0795c6fSMarcus Overhagen m_nodes.end(), 249a0795c6fSMarcus Overhagen node); 250a0795c6fSMarcus Overhagen 251a0795c6fSMarcus Overhagen // should have removed one and only one entry 252a0795c6fSMarcus Overhagen m_nodes.resize(m_nodes.size()-1); 253a0795c6fSMarcus Overhagen 254a0795c6fSMarcus Overhagen // // 6aug99: the timesource is now the sync node... 255a0795c6fSMarcus Overhagen // // is this the sync node? reassign if so 256a0795c6fSMarcus Overhagen // 257a0795c6fSMarcus Overhagen // if(node->node() == m_syncNode) { 258a0795c6fSMarcus Overhagen // 259a0795c6fSMarcus Overhagen // // look for another sync-capable node 260a0795c6fSMarcus Overhagen // bool found = false; 261a0795c6fSMarcus Overhagen // for(int n = 0; !found && n < m_nodes.size(); ++n) 262a0795c6fSMarcus Overhagen // if(setSyncNode(m_nodes[n]->node()) == B_OK) 263a0795c6fSMarcus Overhagen // found = true; 264a0795c6fSMarcus Overhagen // 265a0795c6fSMarcus Overhagen // // no luck? admit defeat: 266a0795c6fSMarcus Overhagen // if(!found) { 267a0795c6fSMarcus Overhagen // PRINT(( 268a0795c6fSMarcus Overhagen // "* NodeGroup::removeNode(): no sync-capable nodes left!\n")); 269a0795c6fSMarcus Overhagen // 270a0795c6fSMarcus Overhagen // // +++++ stop & set to invalid state? 271a0795c6fSMarcus Overhagen // 272a0795c6fSMarcus Overhagen // setSyncNode(media_node::null); 273a0795c6fSMarcus Overhagen // } 274a0795c6fSMarcus Overhagen // } 275a0795c6fSMarcus Overhagen 276a0795c6fSMarcus Overhagen // stop the node if necessary 277a0795c6fSMarcus Overhagen status_t err = node->_stop(); 278a0795c6fSMarcus Overhagen if(err < B_OK) { 279a0795c6fSMarcus Overhagen PRINT(( 280a0795c6fSMarcus Overhagen "*** NodeGroup::removeNode('%s'): error from node->_stop():\n" 281a0795c6fSMarcus Overhagen " %s\n", 282a0795c6fSMarcus Overhagen node->name(), 283a0795c6fSMarcus Overhagen strerror(err))); 284a0795c6fSMarcus Overhagen } 285a0795c6fSMarcus Overhagen 286a0795c6fSMarcus Overhagen // clear the node's group pointer 287a0795c6fSMarcus Overhagen node->_setGroup(0); 288a0795c6fSMarcus Overhagen 289a0795c6fSMarcus Overhagen // release the manager lock; the node is now ungrouped and 290a0795c6fSMarcus Overhagen // unlocked 291a0795c6fSMarcus Overhagen m_manager->unlock(); 292a0795c6fSMarcus Overhagen 293a0795c6fSMarcus Overhagen // was that the last node? stop/disable the transport if so 294a0795c6fSMarcus Overhagen if(!m_nodes.size()) { 295a0795c6fSMarcus Overhagen 296a0795c6fSMarcus Overhagen // +++++ kill sync thread(s) 297a0795c6fSMarcus Overhagen 298a0795c6fSMarcus Overhagen _changeState(TRANSPORT_INVALID); 299a0795c6fSMarcus Overhagen } 300a0795c6fSMarcus Overhagen 301a0795c6fSMarcus Overhagen // send notification 302a0795c6fSMarcus Overhagen if(!LockLooper()) { 303a0795c6fSMarcus Overhagen ASSERT(!"LockLooper() failed."); 304a0795c6fSMarcus Overhagen } 305a0795c6fSMarcus Overhagen BMessage m(M_NODE_REMOVED); 306a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 307a0795c6fSMarcus Overhagen m.AddInt32("nodeID", node->id()); 308a0795c6fSMarcus Overhagen notify(&m); 309a0795c6fSMarcus Overhagen UnlockLooper(); 310a0795c6fSMarcus Overhagen 311a0795c6fSMarcus Overhagen // success 312a0795c6fSMarcus Overhagen return B_OK; 313a0795c6fSMarcus Overhagen } 314a0795c6fSMarcus Overhagen 315a0795c6fSMarcus Overhagen status_t NodeGroup::removeNode( 316a0795c6fSMarcus Overhagen uint32 index) { 317a0795c6fSMarcus Overhagen 318a0795c6fSMarcus Overhagen D_METHOD(( 319a0795c6fSMarcus Overhagen "NodeGroup::removeNode(by index)\n")); 320a0795c6fSMarcus Overhagen 321a0795c6fSMarcus Overhagen // +++++ icky nested lock 322a0795c6fSMarcus Overhagen Autolock _l(this); 323a0795c6fSMarcus Overhagen 324a0795c6fSMarcus Overhagen ASSERT(m_nodes.size() > index); 325a0795c6fSMarcus Overhagen return removeNode(m_nodes[index]); 326a0795c6fSMarcus Overhagen } 327a0795c6fSMarcus Overhagen 328a0795c6fSMarcus Overhagen uint32 NodeGroup::groupFlags() const { 329a0795c6fSMarcus Overhagen Autolock _l(this); 330a0795c6fSMarcus Overhagen return m_flags; 331a0795c6fSMarcus Overhagen } 332a0795c6fSMarcus Overhagen 333a0795c6fSMarcus Overhagen status_t NodeGroup::setGroupFlags( 334a0795c6fSMarcus Overhagen uint32 flags) { 335a0795c6fSMarcus Overhagen Autolock _l(this); 336a0795c6fSMarcus Overhagen m_flags = flags; 337a0795c6fSMarcus Overhagen return B_OK; 338a0795c6fSMarcus Overhagen } 339a0795c6fSMarcus Overhagen 340a0795c6fSMarcus Overhagen 341a0795c6fSMarcus Overhagen // returns true if one or more nodes in the group have cycling 342a0795c6fSMarcus Overhagen // enabled, and the start- and end-positions are valid 343a0795c6fSMarcus Overhagen bool NodeGroup::canCycle() const { 344a0795c6fSMarcus Overhagen Autolock _l(this); 345a0795c6fSMarcus Overhagen 346a0795c6fSMarcus Overhagen return 347a0795c6fSMarcus Overhagen m_cycleNodes.size() > 0 && 348a0795c6fSMarcus Overhagen m_endPosition - m_startPosition > s_minCyclePeriod; 349a0795c6fSMarcus Overhagen } 350a0795c6fSMarcus Overhagen 351a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 352a0795c6fSMarcus Overhagen // *** TRANSPORT POSITIONING (LOCK REQUIRED) 353a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 354a0795c6fSMarcus Overhagen 355a0795c6fSMarcus Overhagen // Fetch the current transport state 356a0795c6fSMarcus Overhagen 357a0795c6fSMarcus Overhagen NodeGroup::transport_state_t NodeGroup::transportState() const { 358a0795c6fSMarcus Overhagen Autolock _l(this); 359a0795c6fSMarcus Overhagen return m_transportState; 360a0795c6fSMarcus Overhagen } 361a0795c6fSMarcus Overhagen 362a0795c6fSMarcus Overhagen // Set the starting media time: 363a0795c6fSMarcus Overhagen // This is the point at which playback will begin in any media 364a0795c6fSMarcus Overhagen // files/documents being played by the nodes in this group. 365a0795c6fSMarcus Overhagen // When cycle mode is enabled, this is the point to which each 366a0795c6fSMarcus Overhagen // node will be seek'd at the end of each cycle (loop). 367a0795c6fSMarcus Overhagen // 368a0795c6fSMarcus Overhagen // The starting time can't be changed in the B_OFFLINE run mode 369a0795c6fSMarcus Overhagen // (this call will return an error.) 370a0795c6fSMarcus Overhagen 371a0795c6fSMarcus Overhagen status_t NodeGroup::setStartPosition( 372a0795c6fSMarcus Overhagen bigtime_t start) { 373a0795c6fSMarcus Overhagen Autolock _l(this); 374a0795c6fSMarcus Overhagen 375a0795c6fSMarcus Overhagen D_METHOD(( 376a0795c6fSMarcus Overhagen "NodeGroup::setStartPosition(%Ld)\n", start)); 377a0795c6fSMarcus Overhagen 378a0795c6fSMarcus Overhagen if( 379a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_RUNNING || 380a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_ROLLING || 381a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_STARTING) { 382a0795c6fSMarcus Overhagen 383a0795c6fSMarcus Overhagen if(m_runMode == BMediaNode::B_OFFLINE) 384a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 385a0795c6fSMarcus Overhagen 386a0795c6fSMarcus Overhagen ASSERT(m_timeSourceObj); 387a0795c6fSMarcus Overhagen 388a0795c6fSMarcus Overhagen if(_cycleValid()) { 389a0795c6fSMarcus Overhagen if(m_timeSourceObj->Now() >= m_cycleDeadline) { 390a0795c6fSMarcus Overhagen // too late to change start position; defer 391a0795c6fSMarcus Overhagen // PRINT((" - deferred\n")); 392a0795c6fSMarcus Overhagen m_newStartPosition = start; 393a0795c6fSMarcus Overhagen m_newStart = true; 394a0795c6fSMarcus Overhagen return B_OK; 395a0795c6fSMarcus Overhagen } 396a0795c6fSMarcus Overhagen 397a0795c6fSMarcus Overhagen // not at deadline yet; fall through to set start position 398a0795c6fSMarcus Overhagen } 399a0795c6fSMarcus Overhagen } 400a0795c6fSMarcus Overhagen 401a0795c6fSMarcus Overhagen m_startPosition = start; 402a0795c6fSMarcus Overhagen 403a0795c6fSMarcus Overhagen // +++++ notify [e.moon 11oct99] 404a0795c6fSMarcus Overhagen 405a0795c6fSMarcus Overhagen return B_OK; 406a0795c6fSMarcus Overhagen } 407a0795c6fSMarcus Overhagen 408a0795c6fSMarcus Overhagen // Fetch the starting position: 409a0795c6fSMarcus Overhagen 410a0795c6fSMarcus Overhagen // +++++ if a previously-set start position was deferred, it won't be 411a0795c6fSMarcus Overhagen // returned yet 412a0795c6fSMarcus Overhagen 413a0795c6fSMarcus Overhagen bigtime_t NodeGroup::startPosition() const { 414a0795c6fSMarcus Overhagen Autolock _l(this); 415a0795c6fSMarcus Overhagen 416a0795c6fSMarcus Overhagen return m_startPosition; 417a0795c6fSMarcus Overhagen } 418a0795c6fSMarcus Overhagen 419a0795c6fSMarcus Overhagen // Set the ending media time: 420a0795c6fSMarcus Overhagen // This is the point at which playback will end relative to 421a0795c6fSMarcus Overhagen // media documents begin played by the nodes in this group; 422a0795c6fSMarcus Overhagen // in cycle mode, this specifies the loop point. If the 423a0795c6fSMarcus Overhagen // ending time is less than or equal to the starting time, 424a0795c6fSMarcus Overhagen // the transport will continue until stopped manually. 425a0795c6fSMarcus Overhagen // If the end position is changed while the transport is playing, 426a0795c6fSMarcus Overhagen // it must take effect retroactively (if it's before the current 427a0795c6fSMarcus Overhagen // position and looping is enabled, all nodes must 'warp' to 428a0795c6fSMarcus Overhagen // the proper post-loop position.) 429a0795c6fSMarcus Overhagen // 430a0795c6fSMarcus Overhagen // The ending time can't be changed if run mode is B_OFFLINE and 431a0795c6fSMarcus Overhagen // the transport is running (this call will return an error.) 432a0795c6fSMarcus Overhagen 433a0795c6fSMarcus Overhagen status_t NodeGroup::setEndPosition( 434a0795c6fSMarcus Overhagen bigtime_t end) { 435a0795c6fSMarcus Overhagen Autolock _l(this); 436a0795c6fSMarcus Overhagen 437a0795c6fSMarcus Overhagen D_METHOD(( 438a0795c6fSMarcus Overhagen "NodeGroup::setEndPosition(%Ld)\n", end)); 439a0795c6fSMarcus Overhagen 440a0795c6fSMarcus Overhagen if( 441a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_RUNNING || 442a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_ROLLING || 443a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_STARTING) { 444a0795c6fSMarcus Overhagen 445a0795c6fSMarcus Overhagen if(m_runMode == BMediaNode::B_OFFLINE) 446a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 447a0795c6fSMarcus Overhagen 448a0795c6fSMarcus Overhagen ASSERT(m_timeSourceObj); 449a0795c6fSMarcus Overhagen 450a0795c6fSMarcus Overhagen bigtime_t endDelta = end - m_endPosition; 451a0795c6fSMarcus Overhagen 452a0795c6fSMarcus Overhagen if(_cycleValid()) { 453a0795c6fSMarcus Overhagen if(m_timeSourceObj->Now() >= m_cycleDeadline + endDelta) { 454a0795c6fSMarcus Overhagen // too late to change end position; defer 455a0795c6fSMarcus Overhagen // PRINT((" - deferred\n")); 456a0795c6fSMarcus Overhagen m_newEndPosition = end; 457a0795c6fSMarcus Overhagen m_newEnd = true; 458a0795c6fSMarcus Overhagen return B_OK; 459a0795c6fSMarcus Overhagen } 460a0795c6fSMarcus Overhagen else { 461a0795c6fSMarcus Overhagen // set new end position 462a0795c6fSMarcus Overhagen m_endPosition = end; 463a0795c6fSMarcus Overhagen 464a0795c6fSMarcus Overhagen // inform thread 465a0795c6fSMarcus Overhagen ASSERT(m_cyclePort); 466a0795c6fSMarcus Overhagen write_port( 467a0795c6fSMarcus Overhagen m_cyclePort, 468a0795c6fSMarcus Overhagen _CYCLE_END_CHANGED, 469a0795c6fSMarcus Overhagen 0, 470a0795c6fSMarcus Overhagen 0); 471a0795c6fSMarcus Overhagen // 472a0795c6fSMarcus Overhagen // // restart nodes' cycle threads with new end position 473a0795c6fSMarcus Overhagen // _cycleInit(m_cycleStart); 474a0795c6fSMarcus Overhagen // for(node_set::iterator it = m_cycleNodes.begin(); 475a0795c6fSMarcus Overhagen // it != m_cycleNodes.end(); ++it) { 476a0795c6fSMarcus Overhagen // (*it)->_scheduleCycle(m_cycleBoundary); 477a0795c6fSMarcus Overhagen // } 478a0795c6fSMarcus Overhagen // return B_OK; 479a0795c6fSMarcus Overhagen } 480a0795c6fSMarcus Overhagen } 481a0795c6fSMarcus Overhagen } 482a0795c6fSMarcus Overhagen 483a0795c6fSMarcus Overhagen m_endPosition = end; 484a0795c6fSMarcus Overhagen 485a0795c6fSMarcus Overhagen // +++++ notify [e.moon 11oct99] 486a0795c6fSMarcus Overhagen 487a0795c6fSMarcus Overhagen return B_OK; 488a0795c6fSMarcus Overhagen } 489a0795c6fSMarcus Overhagen 490a0795c6fSMarcus Overhagen 491a0795c6fSMarcus Overhagen // Fetch the end position: 492a0795c6fSMarcus Overhagen // Note that if the end position is less than or equal to the start 493a0795c6fSMarcus Overhagen // position, it's ignored. 494a0795c6fSMarcus Overhagen 495a0795c6fSMarcus Overhagen // +++++ if a previously-set end position was deferred, it won't be 496a0795c6fSMarcus Overhagen // returned yet 497a0795c6fSMarcus Overhagen 498a0795c6fSMarcus Overhagen bigtime_t NodeGroup::endPosition() const { 499a0795c6fSMarcus Overhagen Autolock _l(this); 500a0795c6fSMarcus Overhagen return m_endPosition; 501a0795c6fSMarcus Overhagen } 502a0795c6fSMarcus Overhagen 503a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 504a0795c6fSMarcus Overhagen // *** TRANSPORT OPERATIONS (LOCK REQUIRED) 505a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 506a0795c6fSMarcus Overhagen 507a0795c6fSMarcus Overhagen // Preroll the group: 508a0795c6fSMarcus Overhagen // Seeks, then prerolls, each node in the group (honoring the 509a0795c6fSMarcus Overhagen // NO_SEEK and NO_PREROLL flags.) This ensures that the group 510a0795c6fSMarcus Overhagen // can start as quickly as possible. 511a0795c6fSMarcus Overhagen // 512a0795c6fSMarcus Overhagen // Does not return until all nodes in the group have been 513a0795c6fSMarcus Overhagen // prepared. 514a0795c6fSMarcus Overhagen 515a0795c6fSMarcus Overhagen status_t NodeGroup::preroll() { 516a0795c6fSMarcus Overhagen D_METHOD(( 517a0795c6fSMarcus Overhagen "NodeGroup::preroll()\n")); 518a0795c6fSMarcus Overhagen 519a0795c6fSMarcus Overhagen Autolock _l(this); 520a0795c6fSMarcus Overhagen return _preroll(); 521a0795c6fSMarcus Overhagen } 522a0795c6fSMarcus Overhagen 523a0795c6fSMarcus Overhagen // Start all nodes in the group: 524a0795c6fSMarcus Overhagen // Nodes with the NO_START_STOP flag aren't molested. 525a0795c6fSMarcus Overhagen 526a0795c6fSMarcus Overhagen status_t NodeGroup::start() { 527a0795c6fSMarcus Overhagen D_METHOD(( 528a0795c6fSMarcus Overhagen "NodeGroup::start()\n")); 529a0795c6fSMarcus Overhagen 530a0795c6fSMarcus Overhagen Autolock _l(this); 531a0795c6fSMarcus Overhagen return _start(); 532a0795c6fSMarcus Overhagen } 533a0795c6fSMarcus Overhagen 534a0795c6fSMarcus Overhagen // Stop all nodes in the group: 535a0795c6fSMarcus Overhagen // Nodes with the NO_START_STOP flag aren't molested. 536a0795c6fSMarcus Overhagen 537a0795c6fSMarcus Overhagen status_t NodeGroup::stop() { 538a0795c6fSMarcus Overhagen D_METHOD(( 539a0795c6fSMarcus Overhagen "NodeGroup::stop()\n")); 540a0795c6fSMarcus Overhagen 541a0795c6fSMarcus Overhagen Autolock _l(this); 542a0795c6fSMarcus Overhagen return _stop(); 543a0795c6fSMarcus Overhagen } 544a0795c6fSMarcus Overhagen 545a0795c6fSMarcus Overhagen // Roll all nodes in the group: 546a0795c6fSMarcus Overhagen // Queues a start and stop atomically (via BMediaRoster::RollNode()). 547a0795c6fSMarcus Overhagen // Returns B_NOT_ALLOWED if endPosition <= startPosition; 548a0795c6fSMarcus Overhagen 549a0795c6fSMarcus Overhagen status_t NodeGroup::roll() { 550a0795c6fSMarcus Overhagen D_METHOD(( 551a0795c6fSMarcus Overhagen "NodeGroup::roll()\n")); 552a0795c6fSMarcus Overhagen 553a0795c6fSMarcus Overhagen Autolock _l(this); 554a0795c6fSMarcus Overhagen return _roll(); 555a0795c6fSMarcus Overhagen } 556a0795c6fSMarcus Overhagen 557a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 558a0795c6fSMarcus Overhagen // *** TIME SOURCE & RUN-MODE OPERATIONS (LOCK REQUIRED) 559a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 560a0795c6fSMarcus Overhagen 561a0795c6fSMarcus Overhagen // time source control: 562a0795c6fSMarcus Overhagen // getTimeSource(): 563a0795c6fSMarcus Overhagen // returns B_ERROR if no time source has been set; otherwise, 564a0795c6fSMarcus Overhagen // returns the node ID of the current time source for all 565a0795c6fSMarcus Overhagen // nodes in the group. 566a0795c6fSMarcus Overhagen // 567a0795c6fSMarcus Overhagen // setTimeSource(): 568a0795c6fSMarcus Overhagen // Calls SetTimeSourceFor() on every node in the group. 569a0795c6fSMarcus Overhagen // The group must be stopped; B_NOT_ALLOWED will be returned 570a0795c6fSMarcus Overhagen // if the state is TRANSPORT_RUNNING or TRANSPORT_ROLLING. 571a0795c6fSMarcus Overhagen 572a0795c6fSMarcus Overhagen status_t NodeGroup::getTimeSource( 573a0795c6fSMarcus Overhagen media_node* outTimeSource) const { 574a0795c6fSMarcus Overhagen Autolock _l(this); 575a0795c6fSMarcus Overhagen 576a0795c6fSMarcus Overhagen if(m_timeSource != media_node::null) { 577a0795c6fSMarcus Overhagen *outTimeSource = m_timeSource; 578a0795c6fSMarcus Overhagen return B_OK; 579a0795c6fSMarcus Overhagen } 580a0795c6fSMarcus Overhagen return B_ERROR; 581a0795c6fSMarcus Overhagen } 582a0795c6fSMarcus Overhagen 583a0795c6fSMarcus Overhagen status_t NodeGroup::setTimeSource( 584a0795c6fSMarcus Overhagen const media_node& timeSource) { 585a0795c6fSMarcus Overhagen 586a0795c6fSMarcus Overhagen Autolock _l(this); 587a0795c6fSMarcus Overhagen 588a0795c6fSMarcus Overhagen if(m_transportState == TRANSPORT_RUNNING || m_transportState == TRANSPORT_ROLLING) 589a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 590a0795c6fSMarcus Overhagen 591a0795c6fSMarcus Overhagen if(m_timeSourceObj) 592a0795c6fSMarcus Overhagen m_timeSourceObj->Release(); 593a0795c6fSMarcus Overhagen 594a0795c6fSMarcus Overhagen m_timeSource = timeSource; 595a0795c6fSMarcus Overhagen 596a0795c6fSMarcus Overhagen // cache a BTimeSource* 597a0795c6fSMarcus Overhagen m_timeSourceObj = m_manager->roster->MakeTimeSourceFor(timeSource); 598a0795c6fSMarcus Overhagen ASSERT(m_timeSourceObj); 599a0795c6fSMarcus Overhagen 600a0795c6fSMarcus Overhagen // apply new time source to all nodes 601a0795c6fSMarcus Overhagen for_each( 602a0795c6fSMarcus Overhagen m_nodes.begin(), 603a0795c6fSMarcus Overhagen m_nodes.end(), 604a0795c6fSMarcus Overhagen bind2nd( 605a0795c6fSMarcus Overhagen mem_fun(&NodeRef::_setTimeSource), 606a0795c6fSMarcus Overhagen m_timeSource.node 607a0795c6fSMarcus Overhagen ) 608a0795c6fSMarcus Overhagen ); 609a0795c6fSMarcus Overhagen 610a0795c6fSMarcus Overhagen // // try to set as sync node 611a0795c6fSMarcus Overhagen // err = setSyncNode(timeSource); 612a0795c6fSMarcus Overhagen // if(err < B_OK) { 613a0795c6fSMarcus Overhagen // PRINT(( 614a0795c6fSMarcus Overhagen // "* NodeGroup::setTimeSource(): setSyncNode() failed: %s\n", 615a0795c6fSMarcus Overhagen // strerror(err))); 616a0795c6fSMarcus Overhagen // } 617a0795c6fSMarcus Overhagen 618a0795c6fSMarcus Overhagen // notify 619a0795c6fSMarcus Overhagen if(!LockLooper()) { 620a0795c6fSMarcus Overhagen ASSERT(!"LockLooper() failed."); 621a0795c6fSMarcus Overhagen } 622a0795c6fSMarcus Overhagen BMessage m(M_TIME_SOURCE_CHANGED); 623a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 624a0795c6fSMarcus Overhagen m.AddInt32("timeSourceID", timeSource.node); 625a0795c6fSMarcus Overhagen notify(&m); 626a0795c6fSMarcus Overhagen UnlockLooper(); 627a0795c6fSMarcus Overhagen 628a0795c6fSMarcus Overhagen return B_OK; 629a0795c6fSMarcus Overhagen } 630a0795c6fSMarcus Overhagen 631a0795c6fSMarcus Overhagen // run mode access: 632a0795c6fSMarcus Overhagen // Sets the default run mode for the group. This will be 633a0795c6fSMarcus Overhagen // applied to every node with a wildcard (0) run mode. 634a0795c6fSMarcus Overhagen // 635a0795c6fSMarcus Overhagen // Special case: if the run mode is B_OFFLINE, it will be 636a0795c6fSMarcus Overhagen // applied to all nodes in the group. 637a0795c6fSMarcus Overhagen 638a0795c6fSMarcus Overhagen BMediaNode::run_mode NodeGroup::runMode() const { 639a0795c6fSMarcus Overhagen Autolock _l(this); 640a0795c6fSMarcus Overhagen return m_runMode; 641a0795c6fSMarcus Overhagen } 642a0795c6fSMarcus Overhagen 643a0795c6fSMarcus Overhagen status_t NodeGroup::setRunMode(BMediaNode::run_mode mode) { 644a0795c6fSMarcus Overhagen Autolock _l(this); 645a0795c6fSMarcus Overhagen 646a0795c6fSMarcus Overhagen m_runMode = mode; 647a0795c6fSMarcus Overhagen 648a0795c6fSMarcus Overhagen // apply to all nodes 649a0795c6fSMarcus Overhagen for_each( 650a0795c6fSMarcus Overhagen m_nodes.begin(), 651a0795c6fSMarcus Overhagen m_nodes.end(), 652a0795c6fSMarcus Overhagen bind2nd( 653a0795c6fSMarcus Overhagen mem_fun(&NodeRef::_setRunModeAuto), 654a0795c6fSMarcus Overhagen m_runMode 655a0795c6fSMarcus Overhagen ) 656a0795c6fSMarcus Overhagen // bound_method( 657a0795c6fSMarcus Overhagen // *this, 658a0795c6fSMarcus Overhagen // &NodeGroup::setRunModeFor) 659a0795c6fSMarcus Overhagen ); 660a0795c6fSMarcus Overhagen 661a0795c6fSMarcus Overhagen 662a0795c6fSMarcus Overhagen return B_OK; 663a0795c6fSMarcus Overhagen } 664a0795c6fSMarcus Overhagen 665a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 666a0795c6fSMarcus Overhagen // *** BHandler 667a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 668a0795c6fSMarcus Overhagen 669a0795c6fSMarcus Overhagen void NodeGroup::MessageReceived( 670a0795c6fSMarcus Overhagen BMessage* message) { 671a0795c6fSMarcus Overhagen 672a0795c6fSMarcus Overhagen // PRINT(( 673a0795c6fSMarcus Overhagen // "NodeGroup::MessageReceived():\n")); 674a0795c6fSMarcus Overhagen // message->PrintToStream(); 675a0795c6fSMarcus Overhagen status_t err; 676a0795c6fSMarcus Overhagen 677a0795c6fSMarcus Overhagen switch(message->what) { 678a0795c6fSMarcus Overhagen case M_SET_TIME_SOURCE: 679a0795c6fSMarcus Overhagen { 680a0795c6fSMarcus Overhagen media_node timeSource; 681a0795c6fSMarcus Overhagen void* data; 682a0795c6fSMarcus Overhagen ssize_t dataSize; 683a0795c6fSMarcus Overhagen err = message->FindData( 684a0795c6fSMarcus Overhagen "timeSourceNode", 685a0795c6fSMarcus Overhagen B_RAW_TYPE, 686a0795c6fSMarcus Overhagen (const void**)&data, 687a0795c6fSMarcus Overhagen &dataSize); 688a0795c6fSMarcus Overhagen if(err < B_OK) { 689a0795c6fSMarcus Overhagen PRINT(( 690a0795c6fSMarcus Overhagen "* NodeGroup::MessageReceived(M_SET_TIME_SOURCE):\n" 691a0795c6fSMarcus Overhagen " no timeSourceNode!\n")); 692a0795c6fSMarcus Overhagen break; 693a0795c6fSMarcus Overhagen } 694a0795c6fSMarcus Overhagen timeSource = *(media_node*)data; 695a0795c6fSMarcus Overhagen 696a0795c6fSMarcus Overhagen setTimeSource(timeSource); 697a0795c6fSMarcus Overhagen } 698a0795c6fSMarcus Overhagen break; 699a0795c6fSMarcus Overhagen 700a0795c6fSMarcus Overhagen case M_SET_RUN_MODE: 701a0795c6fSMarcus Overhagen { 702a0795c6fSMarcus Overhagen uint32 runMode; 703a0795c6fSMarcus Overhagen err = message->FindInt32("runMode", (int32*)&runMode); 704a0795c6fSMarcus Overhagen if(err < B_OK) { 705a0795c6fSMarcus Overhagen PRINT(( 706a0795c6fSMarcus Overhagen "* NodeGroup::MessageReceived(M_SET_RUN_MODE):\n" 707a0795c6fSMarcus Overhagen " no runMode!\n")); 708a0795c6fSMarcus Overhagen break; 709a0795c6fSMarcus Overhagen } 710a0795c6fSMarcus Overhagen 711a0795c6fSMarcus Overhagen if(runMode < BMediaNode::B_OFFLINE || 712a0795c6fSMarcus Overhagen runMode > BMediaNode::B_RECORDING) { 713a0795c6fSMarcus Overhagen PRINT(( 714a0795c6fSMarcus Overhagen "* NodeGroup::MessageReceived(M_SET_RUN_MODE):\n" 715a0795c6fSMarcus Overhagen " invalid run mode (%ld)\n", runMode)); 716a0795c6fSMarcus Overhagen break; 717a0795c6fSMarcus Overhagen } 718a0795c6fSMarcus Overhagen 719a0795c6fSMarcus Overhagen setRunMode((BMediaNode::run_mode)runMode); 720a0795c6fSMarcus Overhagen } 721a0795c6fSMarcus Overhagen break; 722a0795c6fSMarcus Overhagen 723a0795c6fSMarcus Overhagen case M_SET_START_POSITION: 724a0795c6fSMarcus Overhagen { 725a0795c6fSMarcus Overhagen bigtime_t position; 726a0795c6fSMarcus Overhagen err = message->FindInt64("position", (int64*)&position); 727a0795c6fSMarcus Overhagen if(err < B_OK) { 728a0795c6fSMarcus Overhagen PRINT(( 729a0795c6fSMarcus Overhagen "* NodeGroup::MessageReceived(M_SET_START_POSITION):\n" 730a0795c6fSMarcus Overhagen " no position!\n")); 731a0795c6fSMarcus Overhagen break; 732a0795c6fSMarcus Overhagen } 733a0795c6fSMarcus Overhagen setStartPosition(position); 734a0795c6fSMarcus Overhagen } 735a0795c6fSMarcus Overhagen break; 736a0795c6fSMarcus Overhagen 737a0795c6fSMarcus Overhagen case M_SET_END_POSITION: 738a0795c6fSMarcus Overhagen { 739a0795c6fSMarcus Overhagen bigtime_t position; 740a0795c6fSMarcus Overhagen err = message->FindInt64("position", (int64*)&position); 741a0795c6fSMarcus Overhagen if(err < B_OK) { 742a0795c6fSMarcus Overhagen PRINT(( 743a0795c6fSMarcus Overhagen "* NodeGroup::MessageReceived(M_SET_END_POSITION):\n" 744a0795c6fSMarcus Overhagen " no position!\n")); 745a0795c6fSMarcus Overhagen break; 746a0795c6fSMarcus Overhagen } 747a0795c6fSMarcus Overhagen setEndPosition(position); 748a0795c6fSMarcus Overhagen } 749a0795c6fSMarcus Overhagen break; 750a0795c6fSMarcus Overhagen 751a0795c6fSMarcus Overhagen case M_PREROLL: 752a0795c6fSMarcus Overhagen preroll(); 753a0795c6fSMarcus Overhagen break; 754a0795c6fSMarcus Overhagen 755a0795c6fSMarcus Overhagen case M_START: 756a0795c6fSMarcus Overhagen start(); 757a0795c6fSMarcus Overhagen break; 758a0795c6fSMarcus Overhagen 759a0795c6fSMarcus Overhagen case M_STOP: 760a0795c6fSMarcus Overhagen stop(); 761a0795c6fSMarcus Overhagen break; 762a0795c6fSMarcus Overhagen 763a0795c6fSMarcus Overhagen case M_ROLL: 764a0795c6fSMarcus Overhagen roll(); 765a0795c6fSMarcus Overhagen break; 766a0795c6fSMarcus Overhagen 767a0795c6fSMarcus Overhagen default: 768a0795c6fSMarcus Overhagen _inherited::MessageReceived(message); 769a0795c6fSMarcus Overhagen break; 770a0795c6fSMarcus Overhagen } 771a0795c6fSMarcus Overhagen } 772a0795c6fSMarcus Overhagen 773a0795c6fSMarcus Overhagen 774a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 775a0795c6fSMarcus Overhagen // *** IPersistent 776a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 777a0795c6fSMarcus Overhagen 778a0795c6fSMarcus Overhagen // ! 779a0795c6fSMarcus Overhagen #if CORTEX_XML 780a0795c6fSMarcus Overhagen // ! 781a0795c6fSMarcus Overhagen 782a0795c6fSMarcus Overhagen // +++++ 783a0795c6fSMarcus Overhagen 784a0795c6fSMarcus Overhagen // Default constructor 785a0795c6fSMarcus Overhagen NodeGroup::NodeGroup() : 786a0795c6fSMarcus Overhagen m_manager(0) {} // +++++ finish initialization 787a0795c6fSMarcus Overhagen 788a0795c6fSMarcus Overhagen 789a0795c6fSMarcus Overhagen // ! 790a0795c6fSMarcus Overhagen #endif /*CORTEX_XML*/ 791a0795c6fSMarcus Overhagen // ! 792a0795c6fSMarcus Overhagen 793a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 794a0795c6fSMarcus Overhagen // *** IObservable: [19aug99] 795a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 796a0795c6fSMarcus Overhagen 797a0795c6fSMarcus Overhagen void NodeGroup::observerAdded( 798a0795c6fSMarcus Overhagen const BMessenger& observer) { 799a0795c6fSMarcus Overhagen 800a0795c6fSMarcus Overhagen BMessage m(M_OBSERVER_ADDED); 801a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 802a0795c6fSMarcus Overhagen m.AddMessenger("target", BMessenger(this)); 803a0795c6fSMarcus Overhagen observer.SendMessage(&m); 804a0795c6fSMarcus Overhagen } 805a0795c6fSMarcus Overhagen 806a0795c6fSMarcus Overhagen void NodeGroup::observerRemoved( 807a0795c6fSMarcus Overhagen const BMessenger& observer) { 808a0795c6fSMarcus Overhagen 809a0795c6fSMarcus Overhagen BMessage m(M_OBSERVER_REMOVED); 810a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 811a0795c6fSMarcus Overhagen m.AddMessenger("target", BMessenger(this)); 812a0795c6fSMarcus Overhagen observer.SendMessage(&m); 813a0795c6fSMarcus Overhagen } 814a0795c6fSMarcus Overhagen 815a0795c6fSMarcus Overhagen void NodeGroup::notifyRelease() { 816a0795c6fSMarcus Overhagen 817a0795c6fSMarcus Overhagen BMessage m(M_RELEASED); 818a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 819a0795c6fSMarcus Overhagen m.AddMessenger("target", BMessenger(this)); 820a0795c6fSMarcus Overhagen notify(&m); 821a0795c6fSMarcus Overhagen } 822a0795c6fSMarcus Overhagen 823a0795c6fSMarcus Overhagen void NodeGroup::releaseComplete() { 824a0795c6fSMarcus Overhagen // +++++ 825a0795c6fSMarcus Overhagen } 826a0795c6fSMarcus Overhagen 827a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 828a0795c6fSMarcus Overhagen // *** ILockable: pass lock requests to m_lock 829a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 830a0795c6fSMarcus Overhagen 831a0795c6fSMarcus Overhagen bool NodeGroup::lock( 832a0795c6fSMarcus Overhagen lock_t type, 833a0795c6fSMarcus Overhagen bigtime_t timeout) { 834a0795c6fSMarcus Overhagen 835a0795c6fSMarcus Overhagen D_LOCK(("*** NodeGroup::lock(): %ld\n", find_thread(0))); 836a0795c6fSMarcus Overhagen 837a0795c6fSMarcus Overhagen ASSERT(type == WRITE); 838a0795c6fSMarcus Overhagen status_t err = m_lock.LockWithTimeout(timeout); 839a0795c6fSMarcus Overhagen 840a0795c6fSMarcus Overhagen D_LOCK(("*** NodeGroup::lock() ACQUIRED: %ld\n", find_thread(0))); 841a0795c6fSMarcus Overhagen 842a0795c6fSMarcus Overhagen return err == B_OK; 843a0795c6fSMarcus Overhagen } 844a0795c6fSMarcus Overhagen 845a0795c6fSMarcus Overhagen bool NodeGroup::unlock( 846a0795c6fSMarcus Overhagen lock_t type) { 847a0795c6fSMarcus Overhagen 848a0795c6fSMarcus Overhagen D_LOCK(("*** NodeGroup::unlock(): %ld\n", find_thread(0))); 849a0795c6fSMarcus Overhagen 850a0795c6fSMarcus Overhagen ASSERT(type == WRITE); 851a0795c6fSMarcus Overhagen m_lock.Unlock(); 852a0795c6fSMarcus Overhagen 853a0795c6fSMarcus Overhagen D_LOCK(("*** NodeGroup::unlock() RELEASED: %ld\n", find_thread(0))); 854a0795c6fSMarcus Overhagen 855a0795c6fSMarcus Overhagen return true; 856a0795c6fSMarcus Overhagen } 857a0795c6fSMarcus Overhagen 858a0795c6fSMarcus Overhagen bool NodeGroup::isLocked( 859a0795c6fSMarcus Overhagen lock_t type) const { 860a0795c6fSMarcus Overhagen 861a0795c6fSMarcus Overhagen ASSERT(type == WRITE); 862a0795c6fSMarcus Overhagen return m_lock.IsLocked(); 863a0795c6fSMarcus Overhagen } 864a0795c6fSMarcus Overhagen 865a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 866a0795c6fSMarcus Overhagen // *** ctor (accessible to NodeManager) 867a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 868a0795c6fSMarcus Overhagen 869a0795c6fSMarcus Overhagen NodeGroup::NodeGroup( 870a0795c6fSMarcus Overhagen const char* name, 871a0795c6fSMarcus Overhagen NodeManager* manager, 872a0795c6fSMarcus Overhagen BMediaNode::run_mode runMode) : 873a0795c6fSMarcus Overhagen 874a0795c6fSMarcus Overhagen ObservableHandler(name), 875a0795c6fSMarcus Overhagen m_lock("NodeGroup::m_lock"), 876a0795c6fSMarcus Overhagen m_manager(manager), 877a0795c6fSMarcus Overhagen m_id(NextID()), 878a0795c6fSMarcus Overhagen m_name(name), 879a0795c6fSMarcus Overhagen m_flags(0), 880a0795c6fSMarcus Overhagen m_transportState(TRANSPORT_INVALID), 881a0795c6fSMarcus Overhagen m_runMode(runMode), 882a0795c6fSMarcus Overhagen m_timeSourceObj(0), 883a0795c6fSMarcus Overhagen m_released(false), 884a0795c6fSMarcus Overhagen m_cycleThread(0), 885a0795c6fSMarcus Overhagen m_cyclePort(0), 886a0795c6fSMarcus Overhagen m_startPosition(0LL), 887a0795c6fSMarcus Overhagen m_endPosition(0LL), 888a0795c6fSMarcus Overhagen m_newStart(false), 889a0795c6fSMarcus Overhagen m_newEnd(false) { 890a0795c6fSMarcus Overhagen 891a0795c6fSMarcus Overhagen ASSERT(m_manager); 892a0795c6fSMarcus Overhagen 893a0795c6fSMarcus Overhagen if(!m_manager->Lock()) { 894a0795c6fSMarcus Overhagen ASSERT(!"m_manager->Lock() failed"); 895a0795c6fSMarcus Overhagen } 896a0795c6fSMarcus Overhagen m_manager->AddHandler(this); 897a0795c6fSMarcus Overhagen m_manager->Unlock(); 898a0795c6fSMarcus Overhagen 899a0795c6fSMarcus Overhagen // set default time source 900a0795c6fSMarcus Overhagen media_node ts; 901a0795c6fSMarcus Overhagen D_ROSTER(("# roster->GetTimeSource()\n")); 902a0795c6fSMarcus Overhagen status_t err = m_manager->roster->GetTimeSource(&ts); 903a0795c6fSMarcus Overhagen if(err < B_OK) { 904a0795c6fSMarcus Overhagen PRINT(( 905a0795c6fSMarcus Overhagen "*** NodeGroup(): roster->GetTimeSource() failed:\n" 906a0795c6fSMarcus Overhagen " %s\n", strerror(err))); 907a0795c6fSMarcus Overhagen } 908a0795c6fSMarcus Overhagen setTimeSource(ts); 909a0795c6fSMarcus Overhagen } 910a0795c6fSMarcus Overhagen 911a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 912a0795c6fSMarcus Overhagen // *** internal operations 913a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 914a0795c6fSMarcus Overhagen 915a0795c6fSMarcus Overhagen uint32 NodeGroup::s_nextID = 1; 916a0795c6fSMarcus Overhagen uint32 NodeGroup::NextID() { 917a0795c6fSMarcus Overhagen return atomic_add((int32*)&s_nextID, 1); 918a0795c6fSMarcus Overhagen } 919a0795c6fSMarcus Overhagen 920a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 921a0795c6fSMarcus Overhagen // *** ref->group communication (LOCK REQUIRED) 922a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 923a0795c6fSMarcus Overhagen 924a0795c6fSMarcus Overhagen // when a NodeRef's cycle state (ie. looping or not looping) 925a0795c6fSMarcus Overhagen // changes, it must pass that information on via this method 926a0795c6fSMarcus Overhagen 927a0795c6fSMarcus Overhagen void NodeGroup::_refCycleChanged( 928a0795c6fSMarcus Overhagen NodeRef* ref) { 929a0795c6fSMarcus Overhagen assert_locked(this); 930a0795c6fSMarcus Overhagen D_METHOD(( 931a0795c6fSMarcus Overhagen "NodeGroup::_refCycleChanged('%s')\n", 932a0795c6fSMarcus Overhagen ref->name())); 933a0795c6fSMarcus Overhagen 934a0795c6fSMarcus Overhagen if(ref->m_cycle) { 935a0795c6fSMarcus Overhagen _cycleAddRef(ref); 936a0795c6fSMarcus Overhagen } else { 937a0795c6fSMarcus Overhagen _cycleRemoveRef(ref); 938a0795c6fSMarcus Overhagen } 939a0795c6fSMarcus Overhagen 940a0795c6fSMarcus Overhagen // +++++ if running & cycle valid, the node should be properly 941a0795c6fSMarcus Overhagen // seek'd and start'd 942a0795c6fSMarcus Overhagen } 943a0795c6fSMarcus Overhagen 944a0795c6fSMarcus Overhagen 945a0795c6fSMarcus Overhagen // when a cycling node's latency changes, call this method. 946a0795c6fSMarcus Overhagen 947a0795c6fSMarcus Overhagen void NodeGroup::_refLatencyChanged( 948a0795c6fSMarcus Overhagen NodeRef* ref) { 949a0795c6fSMarcus Overhagen assert_locked(this); 950a0795c6fSMarcus Overhagen D_METHOD(( 951a0795c6fSMarcus Overhagen "NodeGroup::_refLatencyChanged('%s')\n", 952a0795c6fSMarcus Overhagen ref->name())); 953a0795c6fSMarcus Overhagen 954a0795c6fSMarcus Overhagen if(!_cycleValid()) 955a0795c6fSMarcus Overhagen return; 956a0795c6fSMarcus Overhagen 957a0795c6fSMarcus Overhagen // remove & replace ref (positions it properly) 958a0795c6fSMarcus Overhagen _cycleRemoveRef(ref); 959a0795c6fSMarcus Overhagen _cycleAddRef(ref); 960a0795c6fSMarcus Overhagen 961a0795c6fSMarcus Overhagen // slap my thread up 962a0795c6fSMarcus Overhagen ASSERT(m_cyclePort); 963a0795c6fSMarcus Overhagen write_port( 964a0795c6fSMarcus Overhagen m_cyclePort, 965a0795c6fSMarcus Overhagen _CYCLE_LATENCY_CHANGED, 966a0795c6fSMarcus Overhagen 0, 967a0795c6fSMarcus Overhagen 0); 968a0795c6fSMarcus Overhagen 969a0795c6fSMarcus Overhagen // +++++ zat it? 970a0795c6fSMarcus Overhagen } 971a0795c6fSMarcus Overhagen 972a0795c6fSMarcus Overhagen // when a NodeRef receives notification that it has been stopped, 973a0795c6fSMarcus Overhagen // but is labeled as still running, it must call this method. 974a0795c6fSMarcus Overhagen // [e.moon 11oct99: roll/B_OFFLINE support] 975a0795c6fSMarcus Overhagen 976a0795c6fSMarcus Overhagen void NodeGroup::_refStopped( 977a0795c6fSMarcus Overhagen NodeRef* ref) { 978a0795c6fSMarcus Overhagen assert_locked(this); 979a0795c6fSMarcus Overhagen D_METHOD(( 980a0795c6fSMarcus Overhagen "NodeGroup::_refStopped('%s')\n", 981a0795c6fSMarcus Overhagen ref->name())); 982a0795c6fSMarcus Overhagen 983a0795c6fSMarcus Overhagen // roll/B_OFFLINE support [e.moon 11oct99] 984a0795c6fSMarcus Overhagen // (check to see if any other nodes in the group are still running; 985a0795c6fSMarcus Overhagen // mark group stopped if not.) 986a0795c6fSMarcus Overhagen if(m_transportState == TRANSPORT_ROLLING) { 987a0795c6fSMarcus Overhagen bool nodesRunning = false; 988a0795c6fSMarcus Overhagen for(node_set::iterator it = m_nodes.begin(); 989a0795c6fSMarcus Overhagen it != m_nodes.end(); ++it) { 990a0795c6fSMarcus Overhagen if((*it)->isRunning()) { 991a0795c6fSMarcus Overhagen nodesRunning = true; 992a0795c6fSMarcus Overhagen break; 993a0795c6fSMarcus Overhagen } 994a0795c6fSMarcus Overhagen } 995a0795c6fSMarcus Overhagen if(!nodesRunning) 996a0795c6fSMarcus Overhagen // the group has stopped; update transport state 997a0795c6fSMarcus Overhagen _changeState(TRANSPORT_STOPPED); 998a0795c6fSMarcus Overhagen 999a0795c6fSMarcus Overhagen } 1000a0795c6fSMarcus Overhagen 1001a0795c6fSMarcus Overhagen } 1002a0795c6fSMarcus Overhagen 1003a0795c6fSMarcus Overhagen 1004a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 1005a0795c6fSMarcus Overhagen // *** transport helpers (LOCK REQUIRED) 1006a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 1007a0795c6fSMarcus Overhagen 1008a0795c6fSMarcus Overhagen 1009a0795c6fSMarcus Overhagen // Preroll all nodes in the group; this is the implementation 1010a0795c6fSMarcus Overhagen // of preroll(). 1011a0795c6fSMarcus Overhagen // *** this method should not be called from the transport thread 1012a0795c6fSMarcus Overhagen // (since preroll operations can block for a relatively long time.) 1013a0795c6fSMarcus Overhagen 1014a0795c6fSMarcus Overhagen status_t NodeGroup::_preroll() { 1015a0795c6fSMarcus Overhagen assert_locked(this); 1016a0795c6fSMarcus Overhagen 1017a0795c6fSMarcus Overhagen D_METHOD(( 1018a0795c6fSMarcus Overhagen "NodeGroup::_preroll()\n")); 1019a0795c6fSMarcus Overhagen 1020a0795c6fSMarcus Overhagen if( 1021a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_RUNNING || 1022a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_ROLLING) 1023a0795c6fSMarcus Overhagen // too late 1024a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 1025a0795c6fSMarcus Overhagen 1026a0795c6fSMarcus Overhagen // * preroll all nodes to the start position 1027a0795c6fSMarcus Overhagen 1028a0795c6fSMarcus Overhagen // +++++ currently, if an error is encountered it's ignored. 1029a0795c6fSMarcus Overhagen // should the whole operation fail if one node couldn't 1030a0795c6fSMarcus Overhagen // be prerolled? 1031a0795c6fSMarcus Overhagen // 1032a0795c6fSMarcus Overhagen // My gut response is 'no', since the preroll step is 1033a0795c6fSMarcus Overhagen // optional, but the caller should have some inkling that 1034a0795c6fSMarcus Overhagen // one of its nodes didn't behave. 1035a0795c6fSMarcus Overhagen 1036a0795c6fSMarcus Overhagen // [e.moon 13oct99] making PPC compiler happy 1037a0795c6fSMarcus Overhagen // for_each( 1038a0795c6fSMarcus Overhagen // m_nodes.begin(), 1039a0795c6fSMarcus Overhagen // m_nodes.end(), 1040a0795c6fSMarcus Overhagen // bind2nd( 1041a0795c6fSMarcus Overhagen // mem_fun(&NodeRef::_preroll), 1042a0795c6fSMarcus Overhagen // m_startPosition 1043a0795c6fSMarcus Overhagen // ) 1044a0795c6fSMarcus Overhagen // ); 1045a0795c6fSMarcus Overhagen for(node_set::iterator it = m_nodes.begin(); 1046a0795c6fSMarcus Overhagen it != m_nodes.end(); ++it) { 1047a0795c6fSMarcus Overhagen (*it)->_preroll(m_startPosition); 1048a0795c6fSMarcus Overhagen } 1049a0795c6fSMarcus Overhagen 1050a0795c6fSMarcus Overhagen // replaces 1051a0795c6fSMarcus Overhagen // bind2nd( 1052a0795c6fSMarcus Overhagen // bound_method(*this, &NodeGroup::prerollNode), 1053a0795c6fSMarcus Overhagen // m_startPosition 1054a0795c6fSMarcus Overhagen // ) 1055a0795c6fSMarcus Overhagen 1056a0795c6fSMarcus Overhagen return B_OK; 1057a0795c6fSMarcus Overhagen } 1058a0795c6fSMarcus Overhagen 1059a0795c6fSMarcus Overhagen 1060a0795c6fSMarcus Overhagen //// functor: calculates latency of each node it's handed, caching 1061a0795c6fSMarcus Overhagen //// the largest one found; includes initial latency if nodes report it. 1062a0795c6fSMarcus Overhagen // 1063a0795c6fSMarcus Overhagen //class NodeGroup::calcLatencyFn { public: 1064a0795c6fSMarcus Overhagen // bigtime_t& maxLatency; 1065a0795c6fSMarcus Overhagen // 1066a0795c6fSMarcus Overhagen // calcLatencyFn(bigtime_t& _m) : maxLatency(_m) {} 1067a0795c6fSMarcus Overhagen // 1068a0795c6fSMarcus Overhagen // void operator()(NodeRef* r) { 1069a0795c6fSMarcus Overhagen // ASSERT(r); 1070a0795c6fSMarcus Overhagen // 1071a0795c6fSMarcus Overhagen //// PRINT(( 1072a0795c6fSMarcus Overhagen //// "# calcLatencyFn(): '%s'\n", 1073a0795c6fSMarcus Overhagen //// r->name())); 1074a0795c6fSMarcus Overhagen // 1075a0795c6fSMarcus Overhagen // if(!(r->node().kind & B_BUFFER_PRODUCER)) { 1076a0795c6fSMarcus Overhagen // // node can't incur latency 1077a0795c6fSMarcus Overhagen //// PRINT(( 1078a0795c6fSMarcus Overhagen //// "- not a producer\n")); 1079a0795c6fSMarcus Overhagen // return; 1080a0795c6fSMarcus Overhagen // } 1081a0795c6fSMarcus Overhagen // 1082a0795c6fSMarcus Overhagen // bigtime_t latency; 1083a0795c6fSMarcus Overhagen // status_t err = 1084a0795c6fSMarcus Overhagen // BMediaRoster::Roster()->GetLatencyFor( 1085a0795c6fSMarcus Overhagen // r->node(), 1086a0795c6fSMarcus Overhagen // &latency); 1087a0795c6fSMarcus Overhagen // if(err < B_OK) { 1088a0795c6fSMarcus Overhagen // PRINT(( 1089a0795c6fSMarcus Overhagen // "* calcLatencyFn: GetLatencyFor() failed: %s\n", 1090a0795c6fSMarcus Overhagen // strerror(err))); 1091a0795c6fSMarcus Overhagen // return; 1092a0795c6fSMarcus Overhagen // } 1093a0795c6fSMarcus Overhagen //// PRINT(("- %Ld\n", latency)); 1094a0795c6fSMarcus Overhagen // 1095a0795c6fSMarcus Overhagen // bigtime_t add; 1096a0795c6fSMarcus Overhagen // err = BMediaRoster::Roster()->GetInitialLatencyFor( 1097a0795c6fSMarcus Overhagen // r->node(), 1098a0795c6fSMarcus Overhagen // &add); 1099a0795c6fSMarcus Overhagen //// PRINT(("- %Ld\n", add)); 1100a0795c6fSMarcus Overhagen // if(err < B_OK) { 1101a0795c6fSMarcus Overhagen // PRINT(( 1102a0795c6fSMarcus Overhagen // "* calcLatencyFn: GetInitialLatencyFor() failed: %s\n", 1103a0795c6fSMarcus Overhagen // strerror(err))); 1104a0795c6fSMarcus Overhagen // } 1105a0795c6fSMarcus Overhagen // else 1106a0795c6fSMarcus Overhagen // latency += add; 1107a0795c6fSMarcus Overhagen // 1108a0795c6fSMarcus Overhagen // if(latency > maxLatency) 1109a0795c6fSMarcus Overhagen // maxLatency = latency; 1110a0795c6fSMarcus Overhagen // 1111a0795c6fSMarcus Overhagen //// PRINT(( 1112a0795c6fSMarcus Overhagen //// "- max latency: %Ld\n", 1113a0795c6fSMarcus Overhagen //// maxLatency)); 1114a0795c6fSMarcus Overhagen // } 1115a0795c6fSMarcus Overhagen //}; 1116a0795c6fSMarcus Overhagen 1117a0795c6fSMarcus Overhagen // Start all nodes in the group; this is the implementation of 1118a0795c6fSMarcus Overhagen // start(). Fails if the run mode is B_OFFLINE; use _roll() instead 1119a0795c6fSMarcus Overhagen // in that case. 1120a0795c6fSMarcus Overhagen // 1121a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from 1122a0795c6fSMarcus Overhagen // an API-implementation method.) 1123a0795c6fSMarcus Overhagen 1124a0795c6fSMarcus Overhagen status_t NodeGroup::_start() { 1125a0795c6fSMarcus Overhagen assert_locked(this); 1126a0795c6fSMarcus Overhagen 1127a0795c6fSMarcus Overhagen D_METHOD(( 1128a0795c6fSMarcus Overhagen "NodeGroup::_start()\n")); 1129a0795c6fSMarcus Overhagen status_t err; 1130a0795c6fSMarcus Overhagen 1131a0795c6fSMarcus Overhagen if(m_transportState != TRANSPORT_STOPPED) 1132a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 1133a0795c6fSMarcus Overhagen 1134a0795c6fSMarcus Overhagen if(m_runMode == BMediaNode::B_OFFLINE) 1135a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 1136a0795c6fSMarcus Overhagen 1137a0795c6fSMarcus Overhagen ASSERT(m_nodes.size()); 1138a0795c6fSMarcus Overhagen 1139a0795c6fSMarcus Overhagen _changeState(TRANSPORT_STARTING); 1140a0795c6fSMarcus Overhagen 1141a0795c6fSMarcus Overhagen // * Find the highest latency in the group 1142a0795c6fSMarcus Overhagen 1143a0795c6fSMarcus Overhagen bigtime_t offset = 0LL; 1144a0795c6fSMarcus Overhagen calcLatencyFn _f(offset); 1145a0795c6fSMarcus Overhagen for_each( 1146a0795c6fSMarcus Overhagen m_nodes.begin(), 1147a0795c6fSMarcus Overhagen m_nodes.end(), 1148a0795c6fSMarcus Overhagen _f); 1149a0795c6fSMarcus Overhagen 1150a0795c6fSMarcus Overhagen offset += s_rosterLatency; 1151a0795c6fSMarcus Overhagen PRINT(( 1152a0795c6fSMarcus Overhagen "- offset: %Ld\n", offset)); 1153a0795c6fSMarcus Overhagen 1154a0795c6fSMarcus Overhagen // * Seek all nodes (in case one or more failed to preroll) 1155a0795c6fSMarcus Overhagen 1156a0795c6fSMarcus Overhagen for(node_set::iterator it = m_nodes.begin(); 1157a0795c6fSMarcus Overhagen it != m_nodes.end(); ++it) { 1158a0795c6fSMarcus Overhagen err = (*it)->_seekStopped(m_startPosition); 1159a0795c6fSMarcus Overhagen if(err < B_OK) { 1160a0795c6fSMarcus Overhagen PRINT(( 1161a0795c6fSMarcus Overhagen "! NodeGroup('%s')::_start():\n" 1162a0795c6fSMarcus Overhagen " ref('%s')->_seekStopped(%Ld) failed:\n" 1163a0795c6fSMarcus Overhagen " %s\n", 1164a0795c6fSMarcus Overhagen name(), (*it)->name(), m_startPosition, 1165a0795c6fSMarcus Overhagen strerror(err))); 1166a0795c6fSMarcus Overhagen 1167a0795c6fSMarcus Overhagen // +++++ continue? 1168a0795c6fSMarcus Overhagen } 1169a0795c6fSMarcus Overhagen } 1170a0795c6fSMarcus Overhagen 1171a0795c6fSMarcus Overhagen // * Start all nodes, allowing for the max latency found 1172a0795c6fSMarcus Overhagen 1173a0795c6fSMarcus Overhagen ASSERT(m_timeSourceObj); 1174a0795c6fSMarcus Overhagen bigtime_t when = m_timeSourceObj->Now() + offset; 1175a0795c6fSMarcus Overhagen 1176a0795c6fSMarcus Overhagen // 10aug99: initialize cycle (loop) settings 1177a0795c6fSMarcus Overhagen if(_cycleValid()) { 1178a0795c6fSMarcus Overhagen _initCycleThread(); 1179a0795c6fSMarcus Overhagen _cycleInit(when); 1180a0795c6fSMarcus Overhagen } 1181a0795c6fSMarcus Overhagen 1182a0795c6fSMarcus Overhagen // start the nodes 1183a0795c6fSMarcus Overhagen for(node_set::iterator it = m_nodes.begin(); 1184a0795c6fSMarcus Overhagen it != m_nodes.end(); ++it) { 1185a0795c6fSMarcus Overhagen err = (*it)->_start(when); 1186a0795c6fSMarcus Overhagen if(err < B_OK) { 1187a0795c6fSMarcus Overhagen PRINT(( 1188a0795c6fSMarcus Overhagen "! NodeGroup('%s')::_start():\n" 1189a0795c6fSMarcus Overhagen " ref('%s')->_start(%Ld) failed:\n" 1190a0795c6fSMarcus Overhagen " %s\n", 1191a0795c6fSMarcus Overhagen name(), (*it)->name(), when, 1192a0795c6fSMarcus Overhagen strerror(err))); 1193a0795c6fSMarcus Overhagen 1194a0795c6fSMarcus Overhagen // +++++ continue? 1195a0795c6fSMarcus Overhagen } 1196a0795c6fSMarcus Overhagen } 1197a0795c6fSMarcus Overhagen 1198a0795c6fSMarcus Overhagen // notify observers 1199a0795c6fSMarcus Overhagen _changeState(TRANSPORT_RUNNING); 1200a0795c6fSMarcus Overhagen return B_OK; 1201a0795c6fSMarcus Overhagen } 1202a0795c6fSMarcus Overhagen 1203a0795c6fSMarcus Overhagen // Stop all nodes in the group; this is the implementation of 1204a0795c6fSMarcus Overhagen // stop(). 1205a0795c6fSMarcus Overhagen // 1206a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from 1207a0795c6fSMarcus Overhagen // an API-implementation method.) 1208a0795c6fSMarcus Overhagen 1209a0795c6fSMarcus Overhagen status_t NodeGroup::_stop() { 1210a0795c6fSMarcus Overhagen 1211a0795c6fSMarcus Overhagen D_METHOD(( 1212a0795c6fSMarcus Overhagen "NodeGroup::_stop()\n")); 1213a0795c6fSMarcus Overhagen 1214a0795c6fSMarcus Overhagen assert_locked(this); 1215a0795c6fSMarcus Overhagen 1216a0795c6fSMarcus Overhagen if( 1217a0795c6fSMarcus Overhagen m_transportState != TRANSPORT_RUNNING && 1218a0795c6fSMarcus Overhagen m_transportState != TRANSPORT_ROLLING) 1219a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 1220a0795c6fSMarcus Overhagen 1221a0795c6fSMarcus Overhagen _changeState(TRANSPORT_STOPPING); 1222a0795c6fSMarcus Overhagen 1223a0795c6fSMarcus Overhagen // * stop the cycle thread if need be 1224a0795c6fSMarcus Overhagen _destroyCycleThread(); 1225a0795c6fSMarcus Overhagen 1226a0795c6fSMarcus Overhagen // * stop all nodes 1227a0795c6fSMarcus Overhagen // +++++ error reports would be nice 1228a0795c6fSMarcus Overhagen 1229a0795c6fSMarcus Overhagen for_each( 1230a0795c6fSMarcus Overhagen m_nodes.begin(), 1231a0795c6fSMarcus Overhagen m_nodes.end(), 1232a0795c6fSMarcus Overhagen mem_fun(&NodeRef::_stop) 1233a0795c6fSMarcus Overhagen ); 1234a0795c6fSMarcus Overhagen 1235a0795c6fSMarcus Overhagen // update transport state 1236a0795c6fSMarcus Overhagen _changeState(TRANSPORT_STOPPED); 1237a0795c6fSMarcus Overhagen 1238a0795c6fSMarcus Overhagen return B_OK; 1239a0795c6fSMarcus Overhagen } 1240a0795c6fSMarcus Overhagen 1241a0795c6fSMarcus Overhagen // Roll all nodes in the group; this is the implementation of 1242a0795c6fSMarcus Overhagen // roll(). 1243a0795c6fSMarcus Overhagen // 1244a0795c6fSMarcus Overhagen // (this may be called from the transport thread or from 1245a0795c6fSMarcus Overhagen // an API-implementation method.) 1246a0795c6fSMarcus Overhagen 1247a0795c6fSMarcus Overhagen status_t NodeGroup::_roll() { 1248a0795c6fSMarcus Overhagen 1249a0795c6fSMarcus Overhagen D_METHOD(( 1250a0795c6fSMarcus Overhagen "NodeGroup::_roll()\n")); 1251a0795c6fSMarcus Overhagen assert_locked(this); 1252a0795c6fSMarcus Overhagen status_t err; 1253a0795c6fSMarcus Overhagen 1254a0795c6fSMarcus Overhagen if(m_transportState != TRANSPORT_STOPPED) 1255a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 1256a0795c6fSMarcus Overhagen 1257a0795c6fSMarcus Overhagen bigtime_t period = m_endPosition - m_startPosition; 1258a0795c6fSMarcus Overhagen if(period <= 0LL) 1259a0795c6fSMarcus Overhagen return B_NOT_ALLOWED; 1260a0795c6fSMarcus Overhagen 1261a0795c6fSMarcus Overhagen _changeState(TRANSPORT_STARTING); 1262a0795c6fSMarcus Overhagen 1263a0795c6fSMarcus Overhagen bigtime_t tpStart = 0LL; 1264a0795c6fSMarcus Overhagen bigtime_t tpStop = period; 1265a0795c6fSMarcus Overhagen 1266a0795c6fSMarcus Overhagen if(m_runMode != BMediaNode::B_OFFLINE) { 1267a0795c6fSMarcus Overhagen 1268a0795c6fSMarcus Overhagen // * Find the highest latency in the group 1269a0795c6fSMarcus Overhagen bigtime_t offset = 0LL; 1270a0795c6fSMarcus Overhagen calcLatencyFn _f(offset); 1271a0795c6fSMarcus Overhagen for_each( 1272a0795c6fSMarcus Overhagen m_nodes.begin(), 1273a0795c6fSMarcus Overhagen m_nodes.end(), 1274a0795c6fSMarcus Overhagen _f); 1275a0795c6fSMarcus Overhagen 1276a0795c6fSMarcus Overhagen offset += s_rosterLatency; 1277a0795c6fSMarcus Overhagen PRINT(( 1278a0795c6fSMarcus Overhagen "- offset: %Ld\n", offset)); 1279a0795c6fSMarcus Overhagen 1280a0795c6fSMarcus Overhagen ASSERT(m_timeSourceObj); 1281a0795c6fSMarcus Overhagen tpStart = m_timeSourceObj->Now() + offset; 1282a0795c6fSMarcus Overhagen tpStop += tpStart; 1283a0795c6fSMarcus Overhagen } 1284a0795c6fSMarcus Overhagen 1285a0795c6fSMarcus Overhagen // * Roll all nodes; watch for errors 1286a0795c6fSMarcus Overhagen bool allFailed = true; 1287a0795c6fSMarcus Overhagen err = B_OK; 1288a0795c6fSMarcus Overhagen for( 1289a0795c6fSMarcus Overhagen node_set::iterator it = m_nodes.begin(); 1290a0795c6fSMarcus Overhagen it != m_nodes.end(); ++it) { 1291a0795c6fSMarcus Overhagen 1292a0795c6fSMarcus Overhagen status_t e = (*it)->_roll( 1293a0795c6fSMarcus Overhagen tpStart, 1294a0795c6fSMarcus Overhagen tpStop, 1295a0795c6fSMarcus Overhagen m_startPosition); 1296a0795c6fSMarcus Overhagen if(e < B_OK) 1297a0795c6fSMarcus Overhagen err = e; 1298a0795c6fSMarcus Overhagen else 1299a0795c6fSMarcus Overhagen allFailed = false; 1300a0795c6fSMarcus Overhagen } 1301a0795c6fSMarcus Overhagen 1302a0795c6fSMarcus Overhagen if(!allFailed) 1303a0795c6fSMarcus Overhagen // notify observers 1304a0795c6fSMarcus Overhagen _changeState(TRANSPORT_ROLLING); 1305a0795c6fSMarcus Overhagen 1306a0795c6fSMarcus Overhagen return err; 1307a0795c6fSMarcus Overhagen } 1308a0795c6fSMarcus Overhagen 1309a0795c6fSMarcus Overhagen 1310a0795c6fSMarcus Overhagen // State transition; notify listeners 1311a0795c6fSMarcus Overhagen // +++++ [18aug99] DANGER: should notification happen in the middle 1312a0795c6fSMarcus Overhagen // of such an operation? 1313a0795c6fSMarcus Overhagen inline void NodeGroup::_changeState( 1314a0795c6fSMarcus Overhagen transport_state_t to) { 1315a0795c6fSMarcus Overhagen 1316a0795c6fSMarcus Overhagen assert_locked(this); 1317a0795c6fSMarcus Overhagen 1318a0795c6fSMarcus Overhagen m_transportState = to; 1319a0795c6fSMarcus Overhagen 1320a0795c6fSMarcus Overhagen if(!LockLooper()) { 1321a0795c6fSMarcus Overhagen ASSERT(!"LockLooper() failed."); 1322a0795c6fSMarcus Overhagen } 1323a0795c6fSMarcus Overhagen BMessage m(M_TRANSPORT_STATE_CHANGED); 1324a0795c6fSMarcus Overhagen m.AddInt32("groupID", id()); 1325a0795c6fSMarcus Overhagen m.AddInt32("transportState", m_transportState); 1326a0795c6fSMarcus Overhagen notify(&m); 1327a0795c6fSMarcus Overhagen UnlockLooper(); 1328a0795c6fSMarcus Overhagen } 1329a0795c6fSMarcus Overhagen 1330a0795c6fSMarcus Overhagen // Enforce a state transition, and notify listeners 1331a0795c6fSMarcus Overhagen inline void NodeGroup::_changeState( 1332a0795c6fSMarcus Overhagen transport_state_t from, 1333a0795c6fSMarcus Overhagen transport_state_t to) { 1334a0795c6fSMarcus Overhagen 1335a0795c6fSMarcus Overhagen assert_locked(this); 1336a0795c6fSMarcus Overhagen ASSERT(m_transportState == from); 1337a0795c6fSMarcus Overhagen 1338a0795c6fSMarcus Overhagen _changeState(to); 1339a0795c6fSMarcus Overhagen } 1340a0795c6fSMarcus Overhagen 1341a0795c6fSMarcus Overhagen 1342a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 1343a0795c6fSMarcus Overhagen // *** cycle thread & helpers (LOCK REQUIRED) 1344a0795c6fSMarcus Overhagen // -------------------------------------------------------- // 1345a0795c6fSMarcus Overhagen 1346a0795c6fSMarcus Overhagen // *** cycle port definitions 1347a0795c6fSMarcus Overhagen 1348a0795c6fSMarcus Overhagen const int32 _portLength = 32; 1349a0795c6fSMarcus Overhagen const char* const _portName = "NodeGroup::m_cyclePort"; 1350a0795c6fSMarcus Overhagen const size_t _portMsgMaxSize = 256; 1351a0795c6fSMarcus Overhagen 1352a0795c6fSMarcus Overhagen 1353a0795c6fSMarcus Overhagen // set up the cycle thread (including its kernel port) 1354a0795c6fSMarcus Overhagen status_t NodeGroup::_initCycleThread() { 1355a0795c6fSMarcus Overhagen assert_locked(this); 1356a0795c6fSMarcus Overhagen status_t err; 1357a0795c6fSMarcus Overhagen D_METHOD(( 1358a0795c6fSMarcus Overhagen "NodeGroup::_initCycleThread()\n")); 1359a0795c6fSMarcus Overhagen 1360a0795c6fSMarcus Overhagen if(m_cycleThread) { 1361a0795c6fSMarcus Overhagen // thread is still alive 1362a0795c6fSMarcus Overhagen err = _destroyCycleThread(); 1363a0795c6fSMarcus Overhagen if(err < B_OK) 1364a0795c6fSMarcus Overhagen return err; 1365a0795c6fSMarcus Overhagen } 1366a0795c6fSMarcus Overhagen 1367a0795c6fSMarcus Overhagen // create 1368a0795c6fSMarcus Overhagen m_cycleThreadDone = false; 1369a0795c6fSMarcus Overhagen m_cycleThread = spawn_thread( 1370a0795c6fSMarcus Overhagen &_CycleThread, 1371a0795c6fSMarcus Overhagen "NodeGroup[cycleThread]", 1372a0795c6fSMarcus Overhagen B_NORMAL_PRIORITY, 1373a0795c6fSMarcus Overhagen (void*)this); 1374a0795c6fSMarcus Overhagen if(m_cycleThread < B_OK) { 1375a0795c6fSMarcus Overhagen PRINT(( 1376a0795c6fSMarcus Overhagen "* NodeGroup::_initCycleThread(): spawn_thread() failed:\n" 1377a0795c6fSMarcus Overhagen " %s\n", 1378a0795c6fSMarcus Overhagen strerror(m_cycleThread))); 1379a0795c6fSMarcus Overhagen return m_cycleThread; 1380a0795c6fSMarcus Overhagen } 1381a0795c6fSMarcus Overhagen 1382a0795c6fSMarcus Overhagen // launch 1383a0795c6fSMarcus Overhagen return resume_thread(m_cycleThread); 1384a0795c6fSMarcus Overhagen } 1385a0795c6fSMarcus Overhagen 1386a0795c6fSMarcus Overhagen // shut down the cycle thread/port 1387a0795c6fSMarcus Overhagen status_t NodeGroup::_destroyCycleThread() { 1388a0795c6fSMarcus Overhagen assert_locked(this); 1389a0795c6fSMarcus Overhagen status_t err; 1390a0795c6fSMarcus Overhagen D_METHOD(( 1391a0795c6fSMarcus Overhagen "NodeGroup::_destroyCycleThread()\n")); 1392a0795c6fSMarcus Overhagen 1393a0795c6fSMarcus Overhagen if(!m_cycleThread) 1394a0795c6fSMarcus Overhagen return B_OK; 1395a0795c6fSMarcus Overhagen 1396a0795c6fSMarcus Overhagen if(!m_cycleThreadDone) { 1397a0795c6fSMarcus Overhagen // kill the thread 1398a0795c6fSMarcus Overhagen ASSERT(m_cyclePort); 1399a0795c6fSMarcus Overhagen err = write_port_etc( 1400a0795c6fSMarcus Overhagen m_cyclePort, 1401a0795c6fSMarcus Overhagen _CYCLE_STOP, 1402a0795c6fSMarcus Overhagen 0, 1403a0795c6fSMarcus Overhagen 0, 1404a0795c6fSMarcus Overhagen B_TIMEOUT, 1405a0795c6fSMarcus Overhagen 10000LL); 1406a0795c6fSMarcus Overhagen 1407a0795c6fSMarcus Overhagen if(err < B_OK) { 1408a0795c6fSMarcus Overhagen // bad thread. die, thread, die. 1409a0795c6fSMarcus Overhagen PRINT(( 1410a0795c6fSMarcus Overhagen "* NodeGroup::_destroyCycleThread(): port write failed; killing.\n")); 1411a0795c6fSMarcus Overhagen delete_port(m_cyclePort); 1412a0795c6fSMarcus Overhagen m_cyclePort = 0; 1413a0795c6fSMarcus Overhagen kill_thread(m_cycleThread); 1414a0795c6fSMarcus Overhagen m_cycleThread = 0; 1415a0795c6fSMarcus Overhagen return B_OK; 1416a0795c6fSMarcus Overhagen } 1417a0795c6fSMarcus Overhagen 1418a0795c6fSMarcus Overhagen // the thread got the message; wait for it to quit 1419a0795c6fSMarcus Overhagen unlock(); 1420a0795c6fSMarcus Overhagen while(wait_for_thread(m_cycleThread, &err) == B_INTERRUPTED) { 1421a0795c6fSMarcus Overhagen PRINT(( 1422a0795c6fSMarcus Overhagen "! wait_for_thread(m_cycleThread, &err) == B_INTERRUPTED\n")); 1423a0795c6fSMarcus Overhagen } 1424a0795c6fSMarcus Overhagen lock(); 1425a0795c6fSMarcus Overhagen } 1426a0795c6fSMarcus Overhagen 1427a0795c6fSMarcus Overhagen // it's up to the thread to close its port 1428a0795c6fSMarcus Overhagen ASSERT(!m_cyclePort); 1429a0795c6fSMarcus Overhagen 1430a0795c6fSMarcus Overhagen m_cycleThread = 0; 1431a0795c6fSMarcus Overhagen 1432a0795c6fSMarcus Overhagen return B_OK; 1433a0795c6fSMarcus Overhagen } 1434a0795c6fSMarcus Overhagen 1435a0795c6fSMarcus Overhagen 1436a0795c6fSMarcus Overhagen // 1) do the current positions specify a valid cycle region? 1437a0795c6fSMarcus Overhagen // 2) are any nodes in the group cycle-enabled? 1438a0795c6fSMarcus Overhagen 1439a0795c6fSMarcus Overhagen bool NodeGroup::_cycleValid() { 1440a0795c6fSMarcus Overhagen assert_locked(this); 1441a0795c6fSMarcus Overhagen return 1442a0795c6fSMarcus Overhagen (m_transportState == TRANSPORT_RUNNING || 1443a0795c6fSMarcus Overhagen m_transportState == TRANSPORT_STARTING) && 1444a0795c6fSMarcus Overhagen canCycle(); 1445a0795c6fSMarcus Overhagen } 1446a0795c6fSMarcus Overhagen 1447a0795c6fSMarcus Overhagen // initialize the cycle members (call when starting) 1448a0795c6fSMarcus Overhagen 1449a0795c6fSMarcus Overhagen void NodeGroup::_cycleInit( 1450a0795c6fSMarcus Overhagen bigtime_t startTime) { 1451a0795c6fSMarcus Overhagen assert_locked(this); 1452a0795c6fSMarcus Overhagen ASSERT(m_cycleNodes.size() > 0); 1453a0795c6fSMarcus Overhagen D_METHOD(( 1454a0795c6fSMarcus Overhagen "NodeGroup::_cycleInit(%Ld)\n", 1455a0795c6fSMarcus Overhagen startTime)); 1456a0795c6fSMarcus Overhagen 1457a0795c6fSMarcus Overhagen // +++++ rescan latencies? 1458a0795c6fSMarcus Overhagen 1459a0795c6fSMarcus Overhagen // figure new boundary & deadline from region length 1460a0795c6fSMarcus Overhagen bigtime_t cyclePeriod = m_endPosition - m_startPosition; 1461a0795c6fSMarcus Overhagen 1462a0795c6fSMarcus Overhagen if(cyclePeriod <= 0) { 1463a0795c6fSMarcus Overhagen // cycle region is no longer valid 1464a0795c6fSMarcus Overhagen m_cycleBoundary = 0LL; 1465a0795c6fSMarcus Overhagen m_cycleDeadline = 0LL; 1466a0795c6fSMarcus Overhagen 1467a0795c6fSMarcus Overhagen // no no no -- deadlocks when the thread calls this method 1468a0795c6fSMarcus Overhagen // // stop the thread 1469a0795c6fSMarcus Overhagen // _destroyCycleThread(); 1470a0795c6fSMarcus Overhagen return; 1471a0795c6fSMarcus Overhagen } 1472a0795c6fSMarcus Overhagen 1473a0795c6fSMarcus Overhagen m_cycleStart = startTime; 1474a0795c6fSMarcus Overhagen m_cycleBoundary = startTime + cyclePeriod; 1475a0795c6fSMarcus Overhagen m_cycleDeadline = m_cycleBoundary - (m_cycleMaxLatency + s_rosterLatency); 1476a0795c6fSMarcus Overhagen } 1477a0795c6fSMarcus Overhagen 1478a0795c6fSMarcus Overhagen 1479a0795c6fSMarcus Overhagen // add a ref to the cycle set (in proper order, based on latency) 1480a0795c6fSMarcus Overhagen void NodeGroup::_cycleAddRef( 1481a0795c6fSMarcus Overhagen NodeRef* ref) { 1482a0795c6fSMarcus Overhagen assert_locked(this); 1483a0795c6fSMarcus Overhagen 1484a0795c6fSMarcus Overhagen // make sure it's not already there 1485a0795c6fSMarcus Overhagen ASSERT(find( 1486a0795c6fSMarcus Overhagen m_cycleNodes.begin(), 1487a0795c6fSMarcus Overhagen m_cycleNodes.end(), 1488a0795c6fSMarcus Overhagen ref) == m_cycleNodes.end()); 1489a0795c6fSMarcus Overhagen 1490a0795c6fSMarcus Overhagen // [re]calc latency if 0 1491a0795c6fSMarcus Overhagen if(!ref->m_latency) 1492a0795c6fSMarcus Overhagen ref->_updateLatency(); 1493a0795c6fSMarcus Overhagen 1494a0795c6fSMarcus Overhagen node_set::iterator it; 1495a0795c6fSMarcus Overhagen for(it = m_cycleNodes.begin(); 1496a0795c6fSMarcus Overhagen it != m_cycleNodes.end(); ++it) { 1497a0795c6fSMarcus Overhagen if(ref->m_latency > (*it)->m_latency) { 1498a0795c6fSMarcus Overhagen m_cycleNodes.insert(it, ref); 1499a0795c6fSMarcus Overhagen break; 1500a0795c6fSMarcus Overhagen } 1501a0795c6fSMarcus Overhagen } 1502a0795c6fSMarcus Overhagen 1503a0795c6fSMarcus Overhagen // not inserted? new ref belongs at the end 1504a0795c6fSMarcus Overhagen if(it == m_cycleNodes.end()) 1505a0795c6fSMarcus Overhagen m_cycleNodes.insert(it, ref); 1506a0795c6fSMarcus Overhagen } 1507a0795c6fSMarcus Overhagen 1508a0795c6fSMarcus Overhagen // remove a ref from the cycle set 1509a0795c6fSMarcus Overhagen void NodeGroup::_cycleRemoveRef( 1510a0795c6fSMarcus Overhagen NodeRef* ref) { 1511a0795c6fSMarcus Overhagen assert_locked(this); 1512a0795c6fSMarcus Overhagen 1513a0795c6fSMarcus Overhagen node_set::iterator it = find( 1514a0795c6fSMarcus Overhagen m_cycleNodes.begin(), 1515a0795c6fSMarcus Overhagen m_cycleNodes.end(), 1516a0795c6fSMarcus Overhagen ref); 1517a0795c6fSMarcus Overhagen ASSERT(it != m_cycleNodes.end()); 1518a0795c6fSMarcus Overhagen m_cycleNodes.erase(it); 1519a0795c6fSMarcus Overhagen } 1520a0795c6fSMarcus Overhagen 1521a0795c6fSMarcus Overhagen bigtime_t NodeGroup::_cycleBoundary() const { 1522a0795c6fSMarcus Overhagen Autolock _l(this); 1523a0795c6fSMarcus Overhagen return m_cycleBoundary; 1524a0795c6fSMarcus Overhagen } 1525a0795c6fSMarcus Overhagen 1526a0795c6fSMarcus Overhagen // cycle thread impl. 1527a0795c6fSMarcus Overhagen /*static*/ 1528a0795c6fSMarcus Overhagen status_t NodeGroup::_CycleThread(void* user) { 1529a0795c6fSMarcus Overhagen ((NodeGroup*)user)->_cycleThread(); 1530a0795c6fSMarcus Overhagen return B_OK; 1531a0795c6fSMarcus Overhagen } 1532a0795c6fSMarcus Overhagen 1533a0795c6fSMarcus Overhagen void NodeGroup::_cycleThread() { 1534a0795c6fSMarcus Overhagen 1535a0795c6fSMarcus Overhagen status_t err; 1536a0795c6fSMarcus Overhagen int32 code; 1537a0795c6fSMarcus Overhagen int32 errorCount = 0; 1538a0795c6fSMarcus Overhagen 1539a0795c6fSMarcus Overhagen // +++++ liability -- if the thread has to be killed, this buffer 1540a0795c6fSMarcus Overhagen // won't be reclaimed 1541a0795c6fSMarcus Overhagen char* msgBuffer = new char[_portMsgMaxSize]; 1542a0795c6fSMarcus Overhagen array_delete<char> _d(msgBuffer); 1543a0795c6fSMarcus Overhagen 1544a0795c6fSMarcus Overhagen // create port 1545a0795c6fSMarcus Overhagen ASSERT(!m_cyclePort); 1546a0795c6fSMarcus Overhagen m_cyclePort = create_port( 1547a0795c6fSMarcus Overhagen _portLength, 1548a0795c6fSMarcus Overhagen _portName); 1549a0795c6fSMarcus Overhagen ASSERT(m_cyclePort >= B_OK); 1550a0795c6fSMarcus Overhagen 1551a0795c6fSMarcus Overhagen // the message-handling loop 1552a0795c6fSMarcus Overhagen bool done = false; 1553a0795c6fSMarcus Overhagen while(!done) { 1554a0795c6fSMarcus Overhagen 1555a0795c6fSMarcus Overhagen // *** wait until it's time to queue the next cycle, or until 1556a0795c6fSMarcus Overhagen // *** a message arrives 1557a0795c6fSMarcus Overhagen 1558a0795c6fSMarcus Overhagen lock(); // **** BEGIN LOCKED SECTION **** 1559a0795c6fSMarcus Overhagen if(!_cycleValid()) { 1560a0795c6fSMarcus Overhagen unlock(); 1561a0795c6fSMarcus Overhagen break; 1562a0795c6fSMarcus Overhagen } 1563a0795c6fSMarcus Overhagen 1564a0795c6fSMarcus Overhagen ASSERT(m_cycleNodes.size() > 0); 1565a0795c6fSMarcus Overhagen ASSERT(m_timeSourceObj); 1566a0795c6fSMarcus Overhagen 1567a0795c6fSMarcus Overhagen bigtime_t maxLatency = m_cycleNodes.front()->m_latency; 1568a0795c6fSMarcus Overhagen bigtime_t wakeUpAt = m_timeSourceObj->RealTimeFor( 1569a0795c6fSMarcus Overhagen m_cycleBoundary, maxLatency + s_rosterLatency); 1570a0795c6fSMarcus Overhagen bigtime_t timeout = wakeUpAt - m_timeSourceObj->RealTime(); 1571a0795c6fSMarcus Overhagen 1572a0795c6fSMarcus Overhagen if(timeout <= 0) { 1573a0795c6fSMarcus Overhagen // +++++ whoops, I'm late. 1574a0795c6fSMarcus Overhagen // +++++ adjust to compensate !!! 1575a0795c6fSMarcus Overhagen PRINT(( 1576a0795c6fSMarcus Overhagen "*** NodeGroup::_cycleThread(): LATE\n" 1577a0795c6fSMarcus Overhagen " by %Ld\n", -timeout)); 1578a0795c6fSMarcus Overhagen } 1579a0795c6fSMarcus Overhagen 1580a0795c6fSMarcus Overhagen // +++++ if timeout is very short, spin until the target time arrives 1581a0795c6fSMarcus Overhagen 1582a0795c6fSMarcus Overhagen unlock(); // **** END LOCKED SECTION **** 1583a0795c6fSMarcus Overhagen 1584a0795c6fSMarcus Overhagen // block until message arrives or it's time to wake up 1585a0795c6fSMarcus Overhagen err = read_port_etc( 1586a0795c6fSMarcus Overhagen m_cyclePort, 1587a0795c6fSMarcus Overhagen &code, 1588a0795c6fSMarcus Overhagen msgBuffer, 1589a0795c6fSMarcus Overhagen _portMsgMaxSize, 1590a0795c6fSMarcus Overhagen B_TIMEOUT, 1591a0795c6fSMarcus Overhagen timeout); 1592a0795c6fSMarcus Overhagen 1593a0795c6fSMarcus Overhagen if(err == B_TIMED_OUT) { 1594a0795c6fSMarcus Overhagen // the time has come to seek my nodes 1595a0795c6fSMarcus Overhagen _handleCycleService(); 1596a0795c6fSMarcus Overhagen continue; 1597a0795c6fSMarcus Overhagen } 1598a0795c6fSMarcus Overhagen else if(err < B_OK) { 1599a0795c6fSMarcus Overhagen // any other error is bad news 1600a0795c6fSMarcus Overhagen PRINT(( 1601a0795c6fSMarcus Overhagen "* NodeGroup::_cycleThread(): read_port error:\n" 1602a0795c6fSMarcus Overhagen " %s\n" 1603a0795c6fSMarcus Overhagen " ABORTING\n\n", strerror(err))); 1604a0795c6fSMarcus Overhagen if(++errorCount > 10) { 1605a0795c6fSMarcus Overhagen PRINT(( 1606a0795c6fSMarcus Overhagen "*** Too many errors; aborting.\n")); 1607a0795c6fSMarcus Overhagen break; 1608a0795c6fSMarcus Overhagen } 1609a0795c6fSMarcus Overhagen continue; 1610a0795c6fSMarcus Overhagen } 1611a0795c6fSMarcus Overhagen 1612a0795c6fSMarcus Overhagen errorCount = 0; 1613a0795c6fSMarcus Overhagen 1614a0795c6fSMarcus Overhagen // process the message 1615a0795c6fSMarcus Overhagen switch(code) { 1616a0795c6fSMarcus Overhagen case _CYCLE_STOP: 1617a0795c6fSMarcus Overhagen // bail 1618a0795c6fSMarcus Overhagen done = true; 1619a0795c6fSMarcus Overhagen break; 1620a0795c6fSMarcus Overhagen 1621a0795c6fSMarcus Overhagen case _CYCLE_END_CHANGED: 1622a0795c6fSMarcus Overhagen case _CYCLE_LATENCY_CHANGED: 1623a0795c6fSMarcus Overhagen // fall through to next loop; for now, these messages 1624a0795c6fSMarcus Overhagen // serve only to slap me out of my stupor and reassess 1625a0795c6fSMarcus Overhagen // the timing situation... 1626a0795c6fSMarcus Overhagen break; 1627a0795c6fSMarcus Overhagen 1628a0795c6fSMarcus Overhagen default: 1629a0795c6fSMarcus Overhagen PRINT(( 1630a0795c6fSMarcus Overhagen "* NodeGroup::_cycleThread(): unknown message code '%ld'\n", code)); 1631a0795c6fSMarcus Overhagen break; 1632a0795c6fSMarcus Overhagen } 1633a0795c6fSMarcus Overhagen } // while(!done) 1634a0795c6fSMarcus Overhagen 1635a0795c6fSMarcus Overhagen 1636a0795c6fSMarcus Overhagen // delete port 1637a0795c6fSMarcus Overhagen delete_port(m_cyclePort); 1638a0795c6fSMarcus Overhagen m_cyclePort = 0; 1639a0795c6fSMarcus Overhagen 1640a0795c6fSMarcus Overhagen // done 1641a0795c6fSMarcus Overhagen m_cycleThreadDone = true; 1642a0795c6fSMarcus Overhagen } 1643a0795c6fSMarcus Overhagen 1644a0795c6fSMarcus Overhagen // cycle service: seek all nodes & initiate next cycle 1645a0795c6fSMarcus Overhagen void NodeGroup::_handleCycleService() { 1646a0795c6fSMarcus Overhagen Autolock _l(this); 1647a0795c6fSMarcus Overhagen // D_METHOD(( 1648a0795c6fSMarcus Overhagen // "NodeGroup::_handleCycleService()\n")); 1649a0795c6fSMarcus Overhagen status_t err; 1650a0795c6fSMarcus Overhagen 1651a0795c6fSMarcus Overhagen if(!_cycleValid()) { 1652a0795c6fSMarcus Overhagen // PRINT(( 1653a0795c6fSMarcus Overhagen // "- _handleCycleService(): cycle not valid; quitting.\n")); 1654a0795c6fSMarcus Overhagen return; 1655a0795c6fSMarcus Overhagen } 1656a0795c6fSMarcus Overhagen 1657a0795c6fSMarcus Overhagen // seek 1658a0795c6fSMarcus Overhagen for(node_set::iterator it = m_cycleNodes.begin(); 1659a0795c6fSMarcus Overhagen it != m_cycleNodes.end(); ++it) { 1660a0795c6fSMarcus Overhagen err = (*it)->_seek( 1661a0795c6fSMarcus Overhagen m_startPosition, 1662a0795c6fSMarcus Overhagen m_cycleBoundary); 1663a0795c6fSMarcus Overhagen if(err < B_OK) { 1664a0795c6fSMarcus Overhagen PRINT(( 1665a0795c6fSMarcus Overhagen "- _handleCycleService(): node('%s')::_seek() failed:\n" 1666a0795c6fSMarcus Overhagen " %s\n", 1667a0795c6fSMarcus Overhagen (*it)->name(), strerror(err))); 1668a0795c6fSMarcus Overhagen } 1669a0795c6fSMarcus Overhagen } 1670a0795c6fSMarcus Overhagen 1671a0795c6fSMarcus Overhagen // update cycle settings 1672a0795c6fSMarcus Overhagen if(m_newStart) { 1673a0795c6fSMarcus Overhagen m_newStart = false; 1674a0795c6fSMarcus Overhagen m_startPosition = m_newStartPosition; 1675a0795c6fSMarcus Overhagen } 1676a0795c6fSMarcus Overhagen if(m_newEnd) { 1677a0795c6fSMarcus Overhagen m_newEnd = false; 1678a0795c6fSMarcus Overhagen m_endPosition = m_newEndPosition; 1679a0795c6fSMarcus Overhagen } 1680a0795c6fSMarcus Overhagen 1681a0795c6fSMarcus Overhagen // prepare next cycle 1682a0795c6fSMarcus Overhagen _cycleInit(m_cycleBoundary); 1683a0795c6fSMarcus Overhagen } 1684a0795c6fSMarcus Overhagen 1685a0795c6fSMarcus Overhagen // END -- NodeGroup.cpp -- 1686