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