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