1 // NodeManager.cpp 2 3 #include "NodeManager.h" 4 5 #include "AddOnHost.h" 6 #include "Connection.h" 7 #include "NodeGroup.h" 8 #include "NodeRef.h" 9 10 #include <Debug.h> 11 #include <MediaRoster.h> 12 13 #include <algorithm> 14 #include <cstring> 15 #include <functional> 16 #include <list> 17 #include <set> 18 19 #include "set_tools.h" 20 #include "functional_tools.h" 21 22 #include "node_manager_impl.h" 23 24 using namespace std; 25 26 __USE_CORTEX_NAMESPACE 27 28 #define D_METHOD(x) //PRINT (x) 29 #define D_MESSAGE(x) //PRINT (x) 30 #define D_ROSTER(x) //PRINT (x) 31 #define D_LOCK(x) //PRINT (x) 32 33 // -------------------------------------------------------- // 34 // messaging constants 35 // -------------------------------------------------------- // 36 37 // B_MEDIA_CONNECTION_BROKEN 38 const char* const _connectionField = "__connection_id"; 39 const char* const _sourceNodeField = "__source_node_id"; 40 const char* const _destNodeField = "__destination_node_id"; 41 42 43 44 45 // -------------------------------------------------------- // 46 // *** hooks 47 // -------------------------------------------------------- // 48 49 // [e.moon 7nov99] these hooks are called during processing of 50 // BMediaRoster messages, before any notification is sent to 51 // observers. For example, if a B_MEDIA_NODES_CREATED message 52 // were received describing 3 new nodes, nodeCreated() would be 53 // called 3 times before the notification was sent. 54 55 void NodeManager::nodeCreated( 56 NodeRef* ref) {} 57 58 void NodeManager::nodeDeleted( 59 const NodeRef* ref) {} 60 61 void NodeManager::connectionMade( 62 Connection* connection) {} 63 64 void NodeManager::connectionBroken( 65 const Connection* connection) {} 66 67 void NodeManager::connectionFailed( 68 const media_output & output, 69 const media_input & input, 70 const media_format & format, 71 status_t error) {} 72 73 // -------------------------------------------------------- // 74 // helpers 75 // -------------------------------------------------------- // 76 77 class _for_each_state { 78 public: 79 // marks nodes visited 80 set<media_node_id> visited; 81 }; 82 83 // [e.moon 28sep99] graph crawling 84 // - does NOT apply operation to origin node. 85 // - if inGroup is non-0, visits only nodes in that group. 86 // 87 // [e.moon 13oct99]: no longer supports locking (use _lockAllGroups() to 88 // be sure all nodes are locked, if necessary.) 89 90 template<class Op> 91 void _do_for_each_connected( 92 NodeManager* manager, 93 NodeRef* origin, 94 NodeGroup* inGroup, 95 bool recurse, 96 Op operation, 97 _for_each_state* state) { 98 99 // PRINT(("### _do_for_each_connected()\n")); 100 101 ASSERT(manager->IsLocked()); 102 103 ASSERT(origin); 104 ASSERT(state); 105 status_t err; 106 107 if(state->visited.find(origin->id()) != state->visited.end()) { 108 // PRINT(("### already visited\n")); 109 // already visited 110 return; 111 } 112 113 // used to walk connections 114 vector<Connection> connections; 115 116 // mark visited 117 state->visited.insert(origin->id()); 118 119 // walk input connections 120 origin->getInputConnections(connections); 121 for(uint32 n = 0; n < connections.size(); ++n) { 122 123 if(!connections[n].isValid()) 124 continue; 125 126 // PRINT(("# source: %ld\n", connections[n].sourceNode())); 127 128 NodeRef* targetRef; 129 err = manager->getNodeRef( 130 connections[n].sourceNode(), 131 &targetRef); 132 ASSERT(err == B_OK); 133 ASSERT(targetRef); 134 135 if(inGroup && targetRef->group() != inGroup) { 136 // PRINT(("# .group mismatch\n")); 137 // don't need to visit 138 return; 139 } 140 141 // invoke operation 142 // if(lockRef) 143 // targetRef->lock(); 144 operation(targetRef); 145 // if(lockRef) 146 // targetRef->unlock(); 147 148 // recurse? 149 if(recurse) 150 _do_for_each_connected( 151 manager, 152 targetRef, 153 inGroup, 154 true, 155 operation, 156 state); 157 } 158 159 // walk output connections 160 connections.clear(); 161 origin->getOutputConnections(connections); 162 for(uint32 n = 0; n < connections.size(); ++n) { 163 // PRINT(("# dest: %ld\n", connections[n].destinationNode())); 164 165 if(!connections[n].isValid()) 166 continue; 167 168 NodeRef* targetRef; 169 err = manager->getNodeRef( 170 connections[n].destinationNode(), 171 &targetRef); 172 ASSERT(err == B_OK); 173 ASSERT(targetRef); 174 175 if(inGroup && targetRef->group() != inGroup) { 176 // PRINT(("# .group mismatch\n")); 177 // don't need to visit 178 return; 179 } 180 181 // invoke operation 182 // if(lockRef) 183 // targetRef->lock(); 184 operation(targetRef); 185 // if(lockRef) 186 // targetRef->unlock(); 187 188 // recurse? 189 if(recurse) 190 _do_for_each_connected( 191 manager, 192 targetRef, 193 inGroup, 194 true, 195 operation, 196 state); 197 } 198 } 199 200 // dtor helpers 201 inline void NodeManager::_clearGroup( 202 NodeGroup* group) { 203 Autolock _l(group); 204 D_METHOD(( 205 "NodeManager::_clearGroup()\n")); 206 207 // stop group before clearing [10aug99] 208 group->_stop(); 209 210 int32 n; 211 while((n = group->countNodes()) > 0) { 212 group->removeNode(n-1); 213 } 214 215 // // [e.moon 7nov99] release the group 216 // status_t err = remove_observer(this, group); 217 // if(err < B_OK) { 218 // // spew diagnostics 219 // PRINT(( 220 // "!!! NodeManager::_clearGroup(): remove_observer(group %ld):\n" 221 // " %s\n", 222 // group->id(), 223 // strerror(err))); 224 // } 225 } 226 227 inline void NodeManager::_freeConnection( 228 Connection* connection) { 229 ASSERT(connection); 230 231 D_METHOD(( 232 "NodeManager::_freeConnection(%ld)\n", connection->id())); 233 status_t err; 234 235 // break if internal & still valid 236 if( 237 connection->isValid() && 238 connection->flags() & Connection::INTERNAL && 239 !(connection->flags() & Connection::LOCKED)) { 240 241 D_METHOD(( 242 "! breaking connection:\n" 243 " source node: %ld\n" 244 " source id: %ld\n" 245 " source port: %ld\n" 246 " dest node: %ld\n" 247 " dest id: %ld\n" 248 " dest port: %ld\n", 249 connection->sourceNode(), 250 connection->source().id, connection->source().port, 251 connection->destinationNode(), 252 connection->destination().id, connection->destination().port)); 253 254 // do it 255 D_ROSTER(("# roster->Disconnect()\n")); 256 err = roster->Disconnect( 257 connection->sourceNode(), 258 connection->source(), 259 connection->destinationNode(), 260 connection->destination()); 261 262 if(err < B_OK) { 263 D_METHOD(( 264 "!!! BMediaRoster::Disconnect('%s' -> '%s') failed:\n" 265 " %s\n", 266 connection->outputName(), connection->inputName(), 267 strerror(err))); 268 } 269 } 270 271 // delete 272 delete connection; 273 } 274 275 // -------------------------------------------------------- // 276 // *** ctor/dtor 277 // -------------------------------------------------------- // 278 279 280 NodeManager::~NodeManager() { 281 D_METHOD(( 282 "~NodeManager()\n")); 283 ASSERT(IsLocked()); 284 285 // make a list of nodes to be released 286 list<NodeRef*> deadNodes; 287 288 for(node_ref_map::const_iterator it = m_nodeRefMap.begin(); 289 it != m_nodeRefMap.end(); ++it) { 290 deadNodes.push_back((*it).second); 291 } 292 293 // ungroup all nodes 294 295 // [e.moon 13oct99] making PPC compiler happy 296 // for_each( 297 // m_nodeGroupSet.begin(), 298 // m_nodeGroupSet.end(), 299 // bound_method( 300 // *this, 301 // &NodeManager::_clearGroup 302 // ) 303 // ); 304 for(node_group_set::iterator it = m_nodeGroupSet.begin(); 305 it != m_nodeGroupSet.end(); ++it) { 306 _clearGroup(*it); 307 } 308 309 // delete groups 310 ptr_set_delete( 311 m_nodeGroupSet.begin(), 312 m_nodeGroupSet.end()); 313 m_nodeGroupSet.clear(); 314 315 316 // deallocate all connections; disconnect internal nodes 317 // [e.moon 13oct99] making PPC compiler happy 318 // for_each( 319 // m_conSourceMap.begin(), 320 // m_conSourceMap.end(), 321 // unary_map_function( 322 // m_conSourceMap, 323 // bound_method( 324 // *this, 325 // &NodeManager::_freeConnection 326 // ) 327 // ) 328 // ); 329 for(con_map::iterator it = m_conSourceMap.begin(); 330 it != m_conSourceMap.end(); ++it) { 331 _freeConnection((*it).second); 332 } 333 m_conSourceMap.clear(); 334 m_conDestinationMap.clear(); 335 336 // release all nodes 337 for(list<NodeRef*>::const_iterator it = deadNodes.begin(); 338 it != deadNodes.end(); ++it) { 339 (*it)->release(); 340 } 341 342 if(m_nodeRefMap.size()) { 343 // +++++ nodes will only remain if they have observers; cope! 344 PRINT(("*** %ld nodes remaining!\n", m_nodeRefMap.size())); 345 346 deadNodes.clear(); 347 for(node_ref_map::const_iterator it = m_nodeRefMap.begin(); 348 it != m_nodeRefMap.end(); ++it) 349 deadNodes.push_back((*it).second); 350 351 ptr_set_delete( 352 deadNodes.begin(), 353 deadNodes.end()); 354 } 355 356 // for_each( 357 // m_nodeRefMap.begin(), 358 // m_nodeRefMap.end(), 359 // unary_map_function( 360 // m_nodeRefMap, 361 // mem_fun( 362 // &NodeRef::release 363 // ) 364 // ) 365 // ); 366 // 367 // // delete all nodes 368 // ptr_map_delete( 369 // m_nodeRefMap.begin(), 370 // m_nodeRefMap.end()); 371 // 372 // 373 // PRINT(( 374 // "~NodeManager() done\n")); 375 // 376 } 377 378 const char* const NodeManager::s_defaultGroupPrefix = "No Name"; 379 const char* const NodeManager::s_timeSourceGroup = "Time Sources"; 380 const char* const NodeManager::s_audioInputGroup = "System Audio Input"; 381 const char* const NodeManager::s_videoInputGroup = "System Video Input"; 382 const char* const NodeManager::s_audioMixerGroup = "System Audio Mixer"; 383 const char* const NodeManager::s_videoOutputGroup = "System Video Output"; 384 385 NodeManager::NodeManager( 386 bool useAddOnHost) : 387 388 ObservableLooper("NodeManager"), 389 roster(BMediaRoster::Roster()), 390 m_audioInputNode(0), 391 m_videoInputNode(0), 392 m_audioMixerNode(0), 393 m_audioOutputNode(0), 394 m_videoOutputNode(0), 395 m_nextConID(1), 396 m_existingNodesInit(false), 397 m_useAddOnHost(useAddOnHost) { 398 399 D_METHOD(( 400 "NodeManager()\n")); 401 402 ASSERT(roster); 403 404 // create refs for common nodes 405 _initCommonNodes(); 406 407 // start the looper 408 Run(); 409 410 // initialize connection to the media roster 411 D_ROSTER(("# roster->StartWatching(%p)\n", this)); 412 roster->StartWatching(BMessenger(this)); 413 } 414 415 // -------------------------------------------------------- // 416 // *** operations 417 // -------------------------------------------------------- // 418 419 // * ACCESS 420 421 // fetches NodeRef corresponding to a given ID; returns 422 // B_BAD_VALUE if no matching entry was found (and writes 423 // a 0 into the provided pointer.) 424 425 status_t NodeManager::getNodeRef( 426 media_node_id id, 427 NodeRef** outRef) const { 428 Autolock _l(this); 429 430 D_METHOD(( 431 "NodeManager::getNodeRef(%ld)\n", id)); 432 433 node_ref_map::const_iterator it = m_nodeRefMap.find(id); 434 if(it == m_nodeRefMap.end()) { 435 *outRef = 0; 436 return B_BAD_VALUE; 437 } 438 439 *outRef = (*it).second; 440 return B_OK; 441 } 442 443 // [13aug99] 444 // fetches Connection corresponding to a given source/destination 445 // on a given node. Returns an invalid connection and B_BAD_VALUE 446 // if no matching connection was found. 447 448 status_t NodeManager::findConnection( 449 media_node_id node, 450 const media_source& source, 451 Connection* outConnection) const { 452 Autolock _l(this); 453 454 D_METHOD(( 455 "NodeManager::findConnection()\n")); 456 ASSERT(source != media_source::null); 457 458 con_map::const_iterator it = m_conSourceMap.lower_bound(node); 459 con_map::const_iterator itEnd = m_conSourceMap.upper_bound(node); 460 for(; it != itEnd; ++it) 461 if((*it).second->source() == source) { 462 // copy connection 463 *outConnection = *((*it).second); 464 return B_OK; 465 } 466 467 *outConnection = Connection(); 468 return B_BAD_VALUE; 469 } 470 471 status_t NodeManager::findConnection( 472 media_node_id node, 473 const media_destination& destination, 474 Connection* outConnection) const { 475 Autolock _l(this); 476 477 D_METHOD(( 478 "NodeManager::findConnection()\n")); 479 ASSERT(destination != media_destination::null); 480 481 con_map::const_iterator it = m_conDestinationMap.lower_bound(node); 482 con_map::const_iterator itEnd = m_conDestinationMap.upper_bound(node); 483 for(; it != itEnd; ++it) 484 if((*it).second->destination() == destination) { 485 // copy connection 486 *outConnection = *((*it).second); 487 return B_OK; 488 } 489 490 *outConnection = Connection(); 491 return B_BAD_VALUE; 492 } 493 494 // [e.moon 28sep99] 495 // fetches a Connection matching the given source and destination 496 // nodes. Returns an invalid connection and B_BAD_VALUE if 497 // no matching connection was found 498 499 status_t NodeManager::findConnection( 500 media_node_id sourceNode, 501 media_node_id destinationNode, 502 Connection* outConnection) const { 503 Autolock _l(this); 504 505 D_METHOD(( 506 "NodeManager::findConnection(source %ld, dest %ld)\n", sourceNode, destinationNode)); 507 508 con_map::const_iterator it = m_conSourceMap.lower_bound(sourceNode); 509 con_map::const_iterator itEnd = m_conSourceMap.upper_bound(sourceNode); 510 for(; it != itEnd; ++it) { 511 if((*it).second->destinationNode() == destinationNode) { 512 *outConnection = *((*it).second); 513 return B_OK; 514 } 515 } 516 517 *outConnection = Connection(); 518 return B_BAD_VALUE; 519 } 520 521 // [e.moon 28sep99] 522 // tries to find a route from 'nodeA' to 'nodeB'; returns 523 // true if one exists, false if not. 524 525 class NodeManager::_find_route_state { 526 public: 527 set<media_node_id> visited; 528 }; 529 530 bool NodeManager::findRoute( 531 media_node_id nodeA, 532 media_node_id nodeB) { 533 Autolock _l(this); 534 535 D_METHOD(( 536 "NodeManager::findRoute(%ld, %ld)\n", nodeA, nodeB)); 537 status_t err; 538 539 NodeRef* ref; 540 err = getNodeRef(nodeA, &ref); 541 if(err < B_OK) { 542 PRINT(( 543 "!!! NodeManager::findRoute(%ld, %ld): no ref for node %ld\n", 544 nodeA, nodeB, nodeA)); 545 return false; 546 } 547 548 _find_route_state st; 549 return _find_route_recurse(ref, nodeB, &st); 550 } 551 552 // implementation of above 553 554 bool NodeManager::_find_route_recurse( 555 NodeRef* origin, 556 media_node_id target, 557 _find_route_state* state) { 558 559 ASSERT(IsLocked()); 560 ASSERT(origin); 561 ASSERT(state); 562 status_t err; 563 564 // node already visited? 565 if(state->visited.find(origin->id()) != state->visited.end()) { 566 return false; 567 } 568 569 // mark node visited 570 state->visited.insert(origin->id()); 571 572 vector<Connection> connections; 573 574 // walk input connections 575 origin->getInputConnections(connections); 576 for(uint32 n = 0; n < connections.size(); ++n) { 577 578 if(!connections[n].isValid()) 579 continue; 580 581 // test against target 582 if(connections[n].sourceNode() == target) 583 return true; // SUCCESS 584 585 // recurse 586 NodeRef* ref; 587 err = getNodeRef( 588 connections[n].sourceNode(), 589 &ref); 590 ASSERT(err == B_OK); 591 ASSERT(ref); 592 593 if(_find_route_recurse( 594 ref, 595 target, 596 state)) 597 return true; // SUCCESS 598 } 599 600 // walk output connections 601 connections.clear(); 602 origin->getOutputConnections(connections); 603 for(uint32 n = 0; n < connections.size(); ++n) { 604 605 if(!connections[n].isValid()) 606 continue; 607 608 // test against target 609 if(connections[n].destinationNode() == target) 610 return true; // SUCCESS 611 612 // recurse 613 NodeRef* ref; 614 err = getNodeRef( 615 connections[n].destinationNode(), 616 &ref); 617 ASSERT(err == B_OK); 618 ASSERT(ref); 619 620 if(_find_route_recurse( 621 ref, 622 target, 623 state)) 624 return true; // SUCCESS 625 } 626 627 return false; // FAILED 628 } 629 630 631 632 // fetches Connection corresponding to a given source or 633 // destination; Returns an invalid connection and B_BAD_VALUE if 634 // none found. 635 // * Note: this is the slowest possible way to look up a 636 // connection. Since the low-level source/destination 637 // structures don't include a node ID, and a destination 638 // port can differ from its node's control port, a linear 639 // search of all known connections is performed. Only 640 // use these methods if you have no clue what node the 641 // connection corresponds to. 642 643 status_t NodeManager::findConnection( 644 const media_source& source, 645 Connection* outConnection) const { 646 Autolock _l(this); 647 648 D_METHOD(( 649 "NodeManager::findConnection()\n")); 650 ASSERT(source != media_source::null); 651 652 for(con_map::const_iterator it = m_conSourceMap.begin(); 653 it != m_conSourceMap.end(); ++it) { 654 if((*it).second->source() == source) { 655 // copy connection 656 *outConnection = *((*it).second); 657 return B_OK; 658 } 659 } 660 661 *outConnection = Connection(); 662 return B_BAD_VALUE; 663 } 664 665 status_t NodeManager::findConnection( 666 const media_destination& destination, 667 Connection* outConnection) const { 668 Autolock _l(this); 669 670 D_METHOD(( 671 "NodeManager::findConnection()\n")); 672 ASSERT(destination != media_destination::null); 673 674 for(con_map::const_iterator it = m_conDestinationMap.begin(); 675 it != m_conDestinationMap.end(); ++it) { 676 if((*it).second->destination() == destination) { 677 // copy connection 678 *outConnection = *((*it).second); 679 return B_OK; 680 } 681 } 682 683 *outConnection = Connection(); 684 return B_BAD_VALUE; 685 } 686 687 688 // fetch NodeRefs for system nodes (if a particular node doesn't 689 // exist, these methods return 0) 690 691 NodeRef* NodeManager::audioInputNode() const { 692 Autolock _l(this); 693 return m_audioInputNode; 694 } 695 NodeRef* NodeManager::videoInputNode() const { 696 Autolock _l(this); 697 return m_videoInputNode; 698 } 699 NodeRef* NodeManager::audioMixerNode() const { 700 Autolock _l(this); 701 return m_audioMixerNode; 702 } 703 NodeRef* NodeManager::audioOutputNode() const { 704 Autolock _l(this); 705 return m_audioOutputNode; 706 } 707 NodeRef* NodeManager::videoOutputNode() const { 708 Autolock _l(this); 709 return m_videoOutputNode; 710 } 711 712 // fetch groups by index 713 // - you can write-lock the manager during sets of calls to these methods; 714 // this ensures that the group set won't change. The methods do lock 715 // the group internally, so locking isn't explicitly required. 716 717 uint32 NodeManager::countGroups() const { 718 Autolock _l(this); 719 D_METHOD(( 720 "NodeManager::countGroups()\n")); 721 722 return m_nodeGroupSet.size(); 723 } 724 725 NodeGroup* NodeManager::groupAt( 726 uint32 index) const { 727 Autolock _l(this); 728 D_METHOD(( 729 "NodeManager::groupAt()\n")); 730 731 return (index < m_nodeGroupSet.size()) ? 732 m_nodeGroupSet[index] : 733 0; 734 } 735 736 // look up a group by unique ID; returns B_BAD_VALUE if no 737 // matching group was found 738 739 class match_group_by_id : 740 public binary_function<const NodeGroup*, uint32, bool> { 741 public: 742 bool operator()(const NodeGroup* group, uint32 id) const { 743 return group->id() == id; 744 } 745 }; 746 747 status_t NodeManager::findGroup( 748 uint32 id, 749 NodeGroup** outGroup) const { 750 Autolock _l(this); 751 D_METHOD(( 752 "NodeManager::findGroup(id)\n")); 753 754 node_group_set::const_iterator it = 755 find_if( 756 m_nodeGroupSet.begin(), 757 m_nodeGroupSet.end(), 758 bind2nd(match_group_by_id(), id) 759 ); 760 761 if(it == m_nodeGroupSet.end()) { 762 *outGroup = 0; 763 return B_BAD_VALUE; 764 } 765 766 *outGroup = *it; 767 return B_OK; 768 } 769 770 // look up a group by name; returns B_NAME_NOT_FOUND if 771 // no group matching the name was found. 772 773 class match_group_by_name : 774 public binary_function<const NodeGroup*, const char*, bool> { 775 public: 776 bool operator()(const NodeGroup* group, const char* name) const { 777 return !strcmp(group->name(), name); 778 } 779 }; 780 781 status_t NodeManager::findGroup( 782 const char* name, 783 NodeGroup** outGroup) const { 784 Autolock _l(this); 785 D_METHOD(( 786 "NodeManager::findGroup(name)\n")); 787 788 node_group_set::const_iterator it = 789 find_if( 790 m_nodeGroupSet.begin(), 791 m_nodeGroupSet.end(), 792 bind2nd(match_group_by_name(), name) 793 ); 794 795 if(it == m_nodeGroupSet.end()) { 796 *outGroup = 0; 797 return B_BAD_VALUE; 798 } 799 800 *outGroup = *it; 801 return B_OK; 802 } 803 804 // merge the given source group to the given destination; 805 // empties and releases the source group 806 807 status_t NodeManager::mergeGroups( 808 NodeGroup* sourceGroup, 809 NodeGroup* destinationGroup) { 810 Autolock _l(this); 811 D_METHOD(( 812 "NodeManager::mergeGroups(name)\n")); 813 814 status_t err; 815 816 // [5feb00 c.lenz] already merged 817 if(sourceGroup->id() == destinationGroup->id()) 818 return B_OK; 819 820 if(sourceGroup->isReleased() || destinationGroup->isReleased()) 821 return B_NOT_ALLOWED; 822 823 for(uint32 n = sourceGroup->countNodes(); n; --n) { 824 NodeRef* node = sourceGroup->nodeAt(n-1); 825 ASSERT(node); 826 err = sourceGroup->removeNode(n-1); 827 ASSERT(err == B_OK); 828 err = destinationGroup->addNode(node); 829 ASSERT(err == B_OK); 830 } 831 832 // [7nov99 e.moon] delete the source group 833 _removeGroup(sourceGroup); 834 sourceGroup->release(); 835 836 return B_OK; 837 } 838 839 // [e.moon 28sep99] 840 // split group: given two nodes currently in the same group 841 // that are not connected (directly OR indirectly), 842 // this method removes outsideNode, and all nodes connected 843 // to outsideNode, from the common group. These nodes are 844 // then added to a new group, returned in 'outGroup'. The 845 // new group has " split" appended to the end of the original 846 // group's name. 847 // 848 // Returns B_NOT_ALLOWED if any of the above conditions aren't 849 // met (ie. the nodes are in different groups or an indirect 850 // route exists from one to the other), or B_OK if the group 851 // was split successfully. 852 853 854 class _changeNodeGroupFn : 855 public unary_function<NodeRef*, void> { 856 public: 857 NodeGroup* newGroup; 858 859 _changeNodeGroupFn( 860 NodeGroup* _newGroup) : newGroup(_newGroup) { 861 ASSERT(newGroup); 862 } 863 864 void operator()( 865 NodeRef* node) { 866 867 PRINT(( 868 "_changeNodeGroupFn(): '%s'\n", node->name())); 869 870 status_t err; 871 NodeGroup* oldGroup = node->group(); 872 if(oldGroup) { 873 err = oldGroup->removeNode(node); 874 ASSERT(err == B_OK); 875 } 876 877 err = newGroup->addNode(node); 878 ASSERT(err == B_OK); 879 } 880 }; 881 882 status_t NodeManager::splitGroup( 883 NodeRef* insideNode, 884 NodeRef* outsideNode, 885 NodeGroup** outGroup) { 886 887 ASSERT(insideNode); 888 ASSERT(outsideNode); 889 890 Autolock _l(this); 891 892 // ensure that no route exists from insideNode to outsideNode 893 if(findRoute(insideNode->id(), outsideNode->id())) { 894 PRINT(( 895 "!!! NodeManager::splitGroup(): route exists from %ld to %ld\n", 896 insideNode->id(), outsideNode->id())); 897 return B_NOT_ALLOWED; 898 } 899 900 // make sure the nodes share a common group 901 NodeGroup* oldGroup = insideNode->group(); 902 if(!oldGroup) { 903 PRINT(( 904 "!!! NodeManager::splitGroup(): invalid group\n", 905 insideNode->id(), outsideNode->id())); 906 return B_NOT_ALLOWED; 907 } 908 if(oldGroup != outsideNode->group()) { 909 PRINT(( 910 "!!! NodeManager::splitGroup(): mismatched groups for %ld and %ld\n", 911 insideNode->id(), outsideNode->id())); 912 return B_NOT_ALLOWED; 913 } 914 915 Autolock _l_old_group(oldGroup); 916 917 // create the new group 918 BString nameBuffer = oldGroup->name(); 919 nameBuffer << " split"; 920 921 NodeGroup* newGroup = createGroup( 922 nameBuffer.String(), 923 oldGroup->runMode()); 924 *outGroup = newGroup; 925 926 // move nodes connected to outsideNode from old to new group 927 _changeNodeGroupFn fn(newGroup); 928 fn(outsideNode); 929 930 _for_each_state st; 931 _do_for_each_connected( 932 this, 933 outsideNode, 934 oldGroup, 935 true, 936 fn, 937 &st); 938 939 // [e.moon 1dec99] a single-node group takes that node's name 940 if(newGroup->countNodes() == 1) 941 newGroup->setName(newGroup->nodeAt(0)->name()); 942 943 if(oldGroup->countNodes() == 1) 944 oldGroup->setName(oldGroup->nodeAt(0)->name()); 945 946 return B_OK; 947 } 948 949 950 // * INSTANTIATION & CONNECTION 951 // Use these calls rather than the associated BMediaRoster() 952 // methods to assure that the nodes and connections you set up 953 // can be properly serialized & reconstituted. 954 955 // basic BMediaRoster::InstantiateDormantNode() wrapper 956 957 status_t NodeManager::instantiate( 958 const dormant_node_info& info, 959 NodeRef** outRef, 960 bigtime_t timeout, 961 uint32 nodeFlags) { 962 963 Autolock _l(this); 964 status_t err; 965 D_METHOD(( 966 "NodeManager::instantiate()\n")); 967 968 // * instantiate 969 970 media_node node; 971 972 if(m_useAddOnHost) { 973 err = AddOnHost::InstantiateDormantNode( 974 info, &node, timeout); 975 976 if(err < B_OK) { 977 node = media_node::null; 978 979 // attempt to relaunch 980 BMessenger mess; 981 err = AddOnHost::Launch(&mess); 982 if(err < B_OK) { 983 PRINT(( 984 "!!! NodeManager::instantiate(): giving up on AddOnHost\n")); 985 986 m_useAddOnHost = false; 987 } 988 else { 989 err = AddOnHost::InstantiateDormantNode( 990 info, &node, timeout); 991 } 992 } 993 } 994 995 if(!m_useAddOnHost || node == media_node::null) { 996 D_ROSTER(( 997 "# roster->InstantiateDormantNode()\n")); 998 err = roster->InstantiateDormantNode(info, &node); 999 } 1000 1001 if(err < B_OK) { 1002 *outRef = 0; 1003 return err; 1004 } 1005 1006 if(node == media_node::null) { 1007 // [e.moon 23oct99] +++++ 1008 // instantiating a soundcard input/output (emu10k or sonic_vibes) 1009 // produces a node ID of -1 (R4.5.2 x86) 1010 // 1011 PRINT(( 1012 "! InstantiateDormantNode(): invalid media node\n")); 1013 1014 // bail out 1015 *outRef = 0; 1016 return B_BAD_INDEX; 1017 } 1018 1019 // * create NodeRef 1020 NodeRef* ref = new NodeRef( 1021 node, 1022 this, 1023 nodeFlags, // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99 1024 NodeRef::_INTERNAL); 1025 1026 ref->_setAddonHint(&info); 1027 _addRef(ref); 1028 1029 // * return it 1030 *outRef = ref; 1031 return B_OK; 1032 } 1033 1034 // SniffRef/Instantiate.../SetRefFor: a one-call interface 1035 // to create a node capable of playing a given media file. 1036 1037 status_t NodeManager::instantiate( 1038 const entry_ref& file, 1039 uint64 requireNodeKinds, 1040 NodeRef** outRef, 1041 bigtime_t timeout, 1042 uint32 nodeFlags, 1043 bigtime_t* outDuration) { 1044 1045 D_METHOD(( 1046 "NodeManager::instantiate(ref)\n")); 1047 1048 // [no lock needed; calls the full form of instantiate()] 1049 1050 status_t err; 1051 1052 // * Find matching add-on 1053 dormant_node_info info; 1054 1055 D_ROSTER(( 1056 "# roster->SniffRef()\n")); 1057 err = roster->SniffRef( 1058 file, 1059 requireNodeKinds, 1060 &info); 1061 if(err < B_OK) { 1062 *outRef = 0; 1063 return err; 1064 } 1065 1066 // * Instantiate 1067 err = instantiate(info, outRef, timeout, nodeFlags); 1068 1069 if(err < B_OK) 1070 return err; 1071 1072 ASSERT(*outRef); 1073 1074 // * Set file to play 1075 bigtime_t dur; 1076 D_ROSTER(("# roster->SetRefFor()\n")); 1077 err = roster->SetRefFor( 1078 (*outRef)->node(), 1079 file, 1080 false, 1081 &dur); 1082 1083 if(err < B_OK) { 1084 PRINT(( 1085 "* SetRefFor() failed: %s\n", strerror(err))); 1086 } 1087 else if(outDuration) 1088 *outDuration = dur; 1089 1090 // * update info [e.moon 29sep99] 1091 Autolock _l(*outRef); 1092 (*outRef)->_setAddonHint(&info, &file); 1093 1094 return err; 1095 } 1096 1097 // use this method to reference nodes internal to your 1098 // application. 1099 1100 status_t NodeManager::reference( 1101 BMediaNode* node, 1102 NodeRef** outRef, 1103 uint32 nodeFlags) { 1104 1105 Autolock _l(this); 1106 D_METHOD(( 1107 "NodeManager::reference()\n")); 1108 1109 // should this node be marked _NO_RELEASE? 1110 NodeRef* ref = new NodeRef(node->Node(), this, nodeFlags, 0); 1111 _addRef(ref); 1112 1113 *outRef = ref; 1114 return B_OK; 1115 } 1116 1117 // the most flexible form of connect(): set the template 1118 // format as you would for BMediaRoster::Connect(). 1119 1120 status_t NodeManager::connect( 1121 const media_output& output, 1122 const media_input& input, 1123 const media_format& templateFormat, 1124 Connection* outConnection /*=0*/) { 1125 1126 Autolock _l(this); 1127 status_t err; 1128 D_METHOD(( 1129 "NodeManager::connect()\n")); 1130 1131 // * Find (& create if necessary) NodeRefs 1132 1133 NodeRef* outputRef; 1134 if(getNodeRef(output.node.node, &outputRef) < B_OK) 1135 outputRef = _addRefFor(output.node, 0); 1136 1137 NodeRef* inputRef; 1138 if(getNodeRef(input.node.node, &inputRef) < B_OK) 1139 inputRef = _addRefFor(input.node, 0); 1140 1141 // * Connect the nodes 1142 1143 media_output finalOutput; 1144 media_input finalInput; 1145 media_format finalFormat = templateFormat; 1146 1147 D_ROSTER(("# roster->Connect()\n")); 1148 err = roster->Connect( 1149 output.source, 1150 input.destination, 1151 &finalFormat, 1152 &finalOutput, 1153 &finalInput); 1154 1155 if(err < B_OK) { 1156 if(outConnection) 1157 *outConnection = Connection(); 1158 connectionFailed(output, input, templateFormat, err); 1159 return err; 1160 } 1161 1162 // * Create Connection instance; mark it INTERNAL 1163 // to automatically remove it upon shutdown. 1164 1165 D_METHOD(( 1166 "! creating connection:\n" 1167 " source id: %ld\n" 1168 " source port: %ld\n" 1169 " dest id: %ld\n" 1170 " dest port: %ld\n", 1171 finalOutput.source.id, finalOutput.source.port, 1172 finalInput.destination.id, finalInput.destination.port)); 1173 1174 uint32 cflags = Connection::INTERNAL; 1175 if(outputRef->m_info.node.kind & B_FILE_INTERFACE) { 1176 // 3aug99: 1177 // workaround for bug 19990802-12798: 1178 // connections involving a file-interface node aren't removed 1179 cflags |= Connection::LOCKED; 1180 } 1181 1182 Connection* con = new Connection( 1183 m_nextConID++, 1184 output.node, 1185 finalOutput.source, 1186 finalOutput.name, 1187 input.node, 1188 finalInput.destination, 1189 finalInput.name, 1190 finalFormat, 1191 cflags); 1192 1193 con->setOutputHint( 1194 output.name, 1195 output.format); 1196 1197 con->setInputHint( 1198 input.name, 1199 input.format); 1200 1201 con->setRequestedFormat( 1202 templateFormat); 1203 1204 _addConnection(con); 1205 1206 // [e.moon 10aug99] 1207 // fetch updated latencies; 1208 // [e.moon 28sep99] 1209 // scan all nodes connected directly OR indirectly to the 1210 // newly-connected nodes and update their latencies -- this includes 1211 // recalculating the node's 'producer delay' if in B_RECORDING mode. 1212 1213 _updateLatenciesFrom(inputRef, true); 1214 1215 // copy connection 1216 if(outConnection) { 1217 *outConnection = *con; 1218 } 1219 return B_OK; 1220 } 1221 1222 // format-guessing form of connect(): tries to find 1223 // a common format between output & input before connection; 1224 // returns B_MEDIA_BAD_FORMAT if no common format appears 1225 // possible. 1226 // 1227 // NOTE: the specifics of the input and output formats are ignored; 1228 // this method only looks at the format type, and properly 1229 // handles wildcards at that level (B_MEDIA_NO_TYPE). 1230 1231 status_t NodeManager::connect( 1232 const media_output& output, 1233 const media_input& input, 1234 Connection* outConnection /*=0*/) { 1235 1236 D_METHOD(( 1237 "NodeManager::connect(guess)\n")); 1238 1239 // [no lock needed; calls the full form of connect()] 1240 1241 // defer to the pickier endpoint 1242 media_format f; 1243 1244 if(output.format.type > B_MEDIA_UNKNOWN_TYPE) { 1245 f = output.format; 1246 if ((input.format.type > B_MEDIA_UNKNOWN_TYPE) && 1247 (f.type != input.format.type)) { 1248 connectionFailed(output, input, f, B_MEDIA_BAD_FORMAT); 1249 return B_MEDIA_BAD_FORMAT; 1250 } 1251 } 1252 else if(input.format.type > B_MEDIA_UNKNOWN_TYPE) { 1253 f = input.format; 1254 // output node doesn't care 1255 } 1256 else { 1257 // about as non-picky as two nodes can possibly be 1258 f.type = B_MEDIA_UNKNOWN_TYPE; 1259 } 1260 1261 // +++++ ? revert to wildcard ? 1262 1263 // let the nodes try to work out a common format from here 1264 return connect( 1265 output, 1266 input, 1267 f, 1268 outConnection); 1269 } 1270 1271 // disconnects the connection represented by the provided 1272 // Connection object. if successful, returns B_OK. 1273 1274 status_t NodeManager::disconnect( 1275 const Connection& connection) { 1276 1277 Autolock _l(this); 1278 status_t err; 1279 D_METHOD(( 1280 "NodeManager::disconnect()\n")); 1281 1282 // don't bother trying to disconnect an invalid connection 1283 if(!connection.isValid()) 1284 return B_NOT_ALLOWED; 1285 1286 // make sure connection can be released 1287 if(connection.flags() & Connection::LOCKED) { 1288 PRINT(( 1289 "NodeManager::disconnect(): connection locked:\n" 1290 " %ld:%s -> %ld:%s\n", 1291 connection.sourceNode(), 1292 connection.outputName(), 1293 connection.destinationNode(), 1294 connection.inputName())); 1295 return B_NOT_ALLOWED; 1296 } 1297 1298 D_METHOD(( 1299 "! breaking connection:\n" 1300 " source node: %ld\n" 1301 " source id: %ld\n" 1302 " source port: %ld\n" 1303 " dest node: %ld\n" 1304 " dest id: %ld\n" 1305 " dest port: %ld\n", 1306 connection.sourceNode(), 1307 connection.source().id, connection.source().port, 1308 connection.destinationNode(), 1309 connection.destination().id, connection.destination().port)); 1310 1311 // do it 1312 D_ROSTER(("# roster->Disconnect()\n")); 1313 err = roster->Disconnect( 1314 connection.sourceNode(), 1315 connection.source(), 1316 connection.destinationNode(), 1317 connection.destination()); 1318 1319 // mark disconnected 1320 if(err == B_OK) { 1321 con_map::iterator it = m_conSourceMap.lower_bound(connection.sourceNode()); 1322 con_map::iterator itEnd = m_conSourceMap.upper_bound(connection.sourceNode()); 1323 for(; it != itEnd; ++it) 1324 if((*it).second->id() == connection.id()) { 1325 (*it).second->m_disconnected = true; 1326 break; 1327 } 1328 ASSERT(it != itEnd); 1329 1330 // [e.moon 28sep99] 1331 // fetch updated latencies; 1332 // scan all nodes connected directly OR indirectly to the 1333 // newly-connected nodes and update their latencies -- this includes 1334 // recalculating the node's 'producer delay' if in B_RECORDING mode. 1335 1336 NodeRef* ref; 1337 if(getNodeRef(connection.sourceNode(), &ref) == B_OK) 1338 _updateLatenciesFrom(ref, true); 1339 if(getNodeRef(connection.destinationNode(), &ref) == B_OK) 1340 _updateLatenciesFrom(ref, true); 1341 1342 } else { 1343 // +++++ if this failed, somebody somewhere is mighty confused 1344 PRINT(( 1345 "NodeManager::disconnect(): Disconnect() failed:\n %s\n", 1346 strerror(err))); 1347 } 1348 1349 return err; 1350 } 1351 1352 // * GROUP CREATION 1353 1354 NodeGroup* NodeManager::createGroup( 1355 const char* name, 1356 BMediaNode::run_mode runMode) { 1357 1358 Autolock _l(this); 1359 D_METHOD(( 1360 "NodeManager::createGroup()\n")); 1361 1362 NodeGroup* g = new NodeGroup(name, this, runMode); 1363 _addGroup(g); 1364 1365 return g; 1366 } 1367 1368 // -------------------------------------------------------- // 1369 // *** node/connection iteration 1370 // *** MUST BE LOCKED for any of these calls 1371 // -------------------------------------------------------- // 1372 1373 // usage: 1374 // For the first call, pass 'cookie' a pointer to a void* set to 0. 1375 // Returns B_BAD_INDEX when the set of nodes has been exhausted (and 1376 // re-zeroes the cookie, cleaning up any unused memory.) 1377 1378 status_t NodeManager::getNextRef( 1379 NodeRef** ref, 1380 void** cookie) { 1381 ASSERT(IsLocked()); 1382 ASSERT(cookie); 1383 1384 if(!*cookie) 1385 *cookie = new node_ref_map::iterator(m_nodeRefMap.begin()); 1386 1387 node_ref_map::iterator* pit = (node_ref_map::iterator*)*cookie; 1388 1389 // at end of set? 1390 if(*pit == m_nodeRefMap.end()) { 1391 delete pit; 1392 *cookie = 0; 1393 return B_BAD_INDEX; 1394 } 1395 1396 // return next entry 1397 *ref = (*(*pit)).second; 1398 ++(*pit); 1399 return B_OK; 1400 } 1401 1402 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++ 1403 void NodeManager::disposeRefCookie( 1404 void** cookie) { 1405 1406 if(!cookie) 1407 return; 1408 1409 node_ref_map::iterator* it = 1410 reinterpret_cast<node_ref_map::iterator*>(*cookie); 1411 ASSERT(it); 1412 if(it) 1413 delete it; 1414 } 1415 1416 status_t NodeManager::getNextConnection( 1417 Connection* connection, 1418 void** cookie) { 1419 ASSERT(IsLocked()); 1420 ASSERT(cookie); 1421 1422 if(!*cookie) 1423 *cookie = new con_map::iterator(m_conSourceMap.begin()); 1424 1425 con_map::iterator* pit = (con_map::iterator*)*cookie; 1426 1427 // at end of set? 1428 if(*pit == m_conSourceMap.end()) { 1429 delete pit; 1430 *cookie = 0; 1431 return B_BAD_INDEX; 1432 } 1433 1434 // return next entry (ewww) 1435 *connection = *((*(*pit)).second); 1436 ++(*pit); 1437 return B_OK; 1438 } 1439 1440 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++ 1441 void NodeManager::disposeConnectionCookie( 1442 void** cookie) { 1443 1444 if(!cookie) 1445 return; 1446 1447 con_map::iterator* it = 1448 reinterpret_cast<con_map::iterator*>(*cookie); 1449 ASSERT(it); 1450 if(it) 1451 delete it; 1452 } 1453 1454 1455 // -------------------------------------------------------- // 1456 // *** BHandler impl 1457 // -------------------------------------------------------- // 1458 1459 // +++++ support all Media Roster messages! +++++ 1460 1461 // [e.moon 7nov99] implemented observer pattern for NodeGroup 1462 void NodeManager::MessageReceived(BMessage* message) { 1463 1464 D_MESSAGE(( 1465 "NodeManager::MessageReceived(): %c%c%c%c\n", 1466 message->what >> 24, 1467 (message->what >> 16) & 0xff, 1468 (message->what >> 8) & 0xff, 1469 (message->what) & 0xff)); 1470 1471 switch(message->what) { 1472 1473 // *** Media Roster messages *** 1474 1475 case B_MEDIA_NODE_CREATED: 1476 if(_handleNodesCreated(message) == B_OK) 1477 notify(message); 1478 break; 1479 1480 case B_MEDIA_NODE_DELETED: 1481 _handleNodesDeleted(message); 1482 notify(message); 1483 break; 1484 1485 case B_MEDIA_CONNECTION_MADE: 1486 _handleConnectionMade(message); 1487 notify(message); 1488 break; 1489 1490 case B_MEDIA_CONNECTION_BROKEN: 1491 _handleConnectionBroken(message); // augments message! 1492 notify(message); 1493 break; 1494 1495 case B_MEDIA_FORMAT_CHANGED: 1496 _handleFormatChanged(message); 1497 notify(message); 1498 break; 1499 1500 default: 1501 _inherited::MessageReceived(message); 1502 break; 1503 } 1504 } 1505 1506 // -------------------------------------------------------- // 1507 // *** IObservable hooks 1508 // -------------------------------------------------------- // 1509 1510 void NodeManager::observerAdded( 1511 const BMessenger& observer) { 1512 1513 BMessage m(M_OBSERVER_ADDED); 1514 m.AddMessenger("target", BMessenger(this)); 1515 observer.SendMessage(&m); 1516 } 1517 1518 1519 void NodeManager::observerRemoved( 1520 const BMessenger& observer) { 1521 1522 BMessage m(M_OBSERVER_REMOVED); 1523 m.AddMessenger("target", BMessenger(this)); 1524 observer.SendMessage(&m); 1525 } 1526 1527 void NodeManager::notifyRelease() { 1528 1529 BMessage m(M_RELEASED); 1530 m.AddMessenger("target", BMessenger(this)); 1531 notify(&m); 1532 } 1533 1534 void NodeManager::releaseComplete() { 1535 // tear down media roster connection 1536 D_ROSTER(("# roster->StopWatching()\n")); 1537 status_t err = roster->StopWatching( 1538 BMessenger(this)); 1539 if(err < B_OK) { 1540 PRINT(( 1541 "* roster->StopWatching() failed: %s\n", strerror(err))); 1542 } 1543 } 1544 1545 1546 // -------------------------------------------------------- // 1547 // *** ILockable impl. 1548 // -------------------------------------------------------- // 1549 1550 bool NodeManager::lock( 1551 lock_t type, 1552 bigtime_t timeout) { 1553 1554 D_LOCK(("*** NodeManager::lock(): %ld\n", find_thread(0))); 1555 1556 status_t err = LockWithTimeout(timeout); 1557 1558 1559 D_LOCK(("*** NodeManager::lock() ACQUIRED: %ld\n", find_thread(0))); 1560 1561 return err == B_OK; 1562 } 1563 1564 bool NodeManager::unlock( 1565 lock_t type) { 1566 1567 D_LOCK(("*** NodeManager::unlock(): %ld\n", find_thread(0))); 1568 1569 Unlock(); 1570 1571 D_LOCK(("*** NodeManager::unlock() RELEASED: %ld\n", find_thread(0))); 1572 1573 return true; 1574 } 1575 1576 bool NodeManager::isLocked( 1577 lock_t type) const { 1578 1579 return IsLocked(); 1580 } 1581 1582 // -------------------------------------------------------- // 1583 // *** internal operations (LOCK REQUIRED) 1584 // -------------------------------------------------------- // 1585 1586 void NodeManager::_initCommonNodes() { 1587 1588 ASSERT(IsLocked()); 1589 status_t err; 1590 media_node node; 1591 1592 D_METHOD(( 1593 "NodeManager::_initCommonNodes()\n")); 1594 1595 uint32 disableTransport = 1596 (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL); 1597 1598 // video input 1599 D_ROSTER(("# roster->GetVideoInput()\n")); 1600 err = roster->GetVideoInput(&node); 1601 if(err == B_OK) 1602 m_videoInputNode = _addRefFor( 1603 node, 1604 _userFlagsForKind(node.kind), 1605 _implFlagsForKind(node.kind)); 1606 1607 // video output 1608 D_ROSTER(("# roster->GetVideoOutput()\n")); 1609 err = roster->GetVideoOutput(&node); 1610 if(err == B_OK) { 1611 if(m_videoInputNode && node.node == m_videoInputNode->id()) { 1612 // input and output nodes identical 1613 // [e.moon 20dec99] 1614 m_videoOutputNode = m_videoInputNode; 1615 } 1616 else { 1617 m_videoOutputNode = _addRefFor( 1618 node, 1619 _userFlagsForKind(node.kind) & ~NodeRef::NO_START_STOP, 1620 _implFlagsForKind(node.kind)); 1621 } 1622 } 1623 1624 // audio mixer 1625 D_ROSTER(("# roster->GetAudioMixer()\n")); 1626 err = roster->GetAudioMixer(&node); 1627 if(err == B_OK) 1628 m_audioMixerNode = _addRefFor( 1629 node, 1630 _userFlagsForKind(node.kind) | disableTransport, 1631 _implFlagsForKind(node.kind)); 1632 1633 // audio input 1634 D_ROSTER(("# roster->GetAudioInput()\n")); 1635 err = roster->GetAudioInput(&node); 1636 if(err == B_OK) 1637 m_audioInputNode = _addRefFor( 1638 node, 1639 _userFlagsForKind(node.kind), 1640 _implFlagsForKind(node.kind)); 1641 1642 // audio output 1643 D_ROSTER(("# roster->GetAudioOutput()\n")); 1644 err = roster->GetAudioOutput(&node); 1645 if(err == B_OK) { 1646 if(m_audioInputNode && node.node == m_audioInputNode->id()) { 1647 // input and output nodes identical 1648 // [e.moon 20dec99] 1649 m_audioOutputNode = m_audioInputNode; 1650 1651 // disable transport controls (the default audio output must always 1652 // be running, and can't be seeked.) 1653 1654 m_audioOutputNode->setFlags( 1655 m_audioOutputNode->flags() | disableTransport); 1656 } 1657 else { 1658 m_audioOutputNode = _addRefFor( 1659 node, 1660 _userFlagsForKind(node.kind) | disableTransport, 1661 _implFlagsForKind(node.kind)); 1662 } 1663 } 1664 } 1665 1666 void NodeManager::_addRef( 1667 NodeRef* ref) { 1668 1669 ASSERT(ref); 1670 ASSERT(IsLocked()); 1671 1672 D_METHOD(( 1673 "NodeManager::_addRef()\n")); 1674 1675 // precondition: no NodeRef yet exists for this node 1676 // +++++ 1677 // [e.moon 21oct99] 1678 // <markjan@xs4all.nl> sez this fails on startup w/ MediaKit 10.5 1679 ASSERT( 1680 m_nodeRefMap.find(ref->id()) == m_nodeRefMap.end()); 1681 1682 // add it 1683 // [e.moon 13oct99] PPC-friendly 1684 m_nodeRefMap.insert(node_ref_map::value_type(ref->id(), ref)); 1685 1686 // [e.moon 8nov99] call hook 1687 nodeCreated(ref); 1688 } 1689 1690 void NodeManager::_removeRef( 1691 media_node_id id) { 1692 ASSERT(IsLocked()); 1693 1694 D_METHOD(( 1695 "NodeManager::_removeRef()\n")); 1696 1697 node_ref_map::iterator it = m_nodeRefMap.find(id); 1698 1699 // precondition: a NodeRef w/ matching ID is in the map 1700 ASSERT(it != m_nodeRefMap.end()); 1701 1702 // [e.moon 8nov99] call hook 1703 nodeDeleted((*it).second); 1704 1705 // remove it 1706 m_nodeRefMap.erase(it); 1707 } 1708 1709 // create, add, return a NodeRef for the given external node; 1710 // must not already exist 1711 NodeRef* NodeManager::_addRefFor( 1712 const media_node& node, 1713 uint32 nodeFlags, 1714 uint32 nodeImplFlags) { 1715 1716 ASSERT(IsLocked()); 1717 1718 D_METHOD(( 1719 "NodeManager::_addRefFor()\n")); 1720 1721 // precondition: no NodeRef yet exists for this node 1722 ASSERT( 1723 m_nodeRefMap.find(node.node) == m_nodeRefMap.end()); 1724 1725 // // precondition: the node actually exists 1726 // live_node_info info; 1727 // D_ROSTER(("# roster->GetLiveNodeInfo()\n")); 1728 // ASSERT(roster->GetLiveNodeInfo(node, &info) == B_OK); 1729 1730 // * create & add ref 1731 NodeRef* ref = new NodeRef(node, this, nodeFlags, nodeImplFlags); 1732 _addRef(ref); 1733 1734 return ref; 1735 } 1736 1737 void NodeManager::_addConnection( 1738 Connection* connection) { 1739 1740 ASSERT(connection); 1741 ASSERT(IsLocked()); 1742 1743 D_METHOD(( 1744 "NodeManager::_addConnection()\n")); 1745 1746 // precondition: not already entered in either source or dest map 1747 // +++++ a more rigorous test would be a very good thing 1748 #ifdef DEBUG 1749 for(con_map::iterator it = m_conSourceMap.lower_bound(connection->sourceNode()); 1750 it != m_conSourceMap.upper_bound(connection->sourceNode()); ++it) { 1751 ASSERT((*it).second->id() != connection->id()); 1752 } 1753 for(con_map::iterator it = m_conDestinationMap.lower_bound(connection->destinationNode()); 1754 it != m_conDestinationMap.upper_bound(connection->destinationNode()); ++it) { 1755 ASSERT((*it).second->id() != connection->id()); 1756 } 1757 #endif 1758 1759 // add to both maps 1760 // [e.moon 13oct99] PPC-friendly 1761 m_conSourceMap.insert( 1762 con_map::value_type( 1763 connection->sourceNode(), 1764 connection)); 1765 m_conDestinationMap.insert( 1766 con_map::value_type( 1767 connection->destinationNode(), 1768 connection)); 1769 1770 // [e.moon 8nov99] call hook 1771 connectionMade(connection); 1772 } 1773 1774 void NodeManager::_removeConnection( 1775 const Connection& connection) { 1776 1777 ASSERT(IsLocked()); 1778 con_map::iterator itSource, itDestination; 1779 1780 D_METHOD(( 1781 "NodeManager::_removeConnection()\n")); 1782 1783 // [e.moon 8nov99] call hook 1784 connectionBroken(&connection); 1785 1786 // precondition: one entry in both source & dest maps 1787 // +++++ a more rigorous test would be a very good thing 1788 1789 for( 1790 itSource = m_conSourceMap.lower_bound(connection.sourceNode()); 1791 itSource != m_conSourceMap.upper_bound(connection.sourceNode()); 1792 ++itSource) 1793 if((*itSource).second->id() == connection.id()) 1794 break; 1795 1796 ASSERT(itSource != m_conSourceMap.end()); 1797 1798 for( 1799 itDestination = m_conDestinationMap.lower_bound(connection.destinationNode()); 1800 itDestination != m_conDestinationMap.upper_bound(connection.destinationNode()); 1801 ++itDestination) 1802 if((*itDestination).second->id() == connection.id()) 1803 break; 1804 1805 ASSERT(itDestination != m_conDestinationMap.end()); 1806 1807 // delete & remove from both maps 1808 delete (*itSource).second; 1809 m_conSourceMap.erase(itSource); 1810 m_conDestinationMap.erase(itDestination); 1811 } 1812 1813 void NodeManager::_addGroup( 1814 NodeGroup* group) { 1815 1816 ASSERT(group); 1817 ASSERT(IsLocked()); 1818 1819 D_METHOD(( 1820 "NodeManager::_addGroup()\n")); 1821 1822 // precondition: group not already in set 1823 ASSERT( 1824 find( 1825 m_nodeGroupSet.begin(), 1826 m_nodeGroupSet.end(), 1827 group) == m_nodeGroupSet.end()); 1828 1829 // add 1830 m_nodeGroupSet.push_back(group); 1831 1832 // // [e.moon 7nov99] observe 1833 // add_observer(this, group); 1834 } 1835 1836 void NodeManager::_removeGroup( 1837 NodeGroup* group) { 1838 1839 ASSERT(group); 1840 ASSERT(IsLocked()); 1841 1842 D_METHOD(( 1843 "NodeManager::_removeGroup()\n")); 1844 1845 node_group_set::iterator it = find( 1846 m_nodeGroupSet.begin(), 1847 m_nodeGroupSet.end(), 1848 group); 1849 1850 // precondition: group in set 1851 if(it == m_nodeGroupSet.end()) { 1852 PRINT(( 1853 "* NodeManager::_removeGroup(%ld): group not in set.\n", 1854 group->id())); 1855 return; 1856 } 1857 1858 // remove it 1859 m_nodeGroupSet.erase(it); 1860 } 1861 1862 // -------------------------------------------------------- // 1863 // *** Message Handlers *** 1864 // -------------------------------------------------------- // 1865 1866 1867 // now returns B_OK iff the message should be relayed to observers 1868 // [e.moon 11oct99] 1869 1870 inline status_t NodeManager::_handleNodesCreated( 1871 BMessage* message) { 1872 ASSERT(IsLocked()); 1873 1874 status_t err = B_OK; 1875 1876 // fetch number of new nodes 1877 type_code type; 1878 int32 count; 1879 err = message->GetInfo("media_node_id", &type, &count); 1880 if(err < B_OK) { 1881 PRINT(( 1882 "* NodeManager::_handleNodesCreated(): GetInfo() failed:\n" 1883 " %s\n", 1884 strerror(err))); 1885 return err; 1886 } 1887 if(!count) { 1888 PRINT(( 1889 "* NodeManager::_handleNodesCreated(): no node IDs in message.\n")); 1890 return err; 1891 } 1892 1893 D_METHOD(( 1894 "NodeManager::_handleNodesCreated(): %d nodes\n", 1895 count)); 1896 1897 // * Create NodeRef instances for the listed nodes. 1898 // If this is the first message received from the Media Roster, 1899 // no connection info will be received for these nodes; store them 1900 // for now (indexed by service-thread port) and figure the connections 1901 // afterwards. 1902 // These nodes are mapped by port ID because that's the only criterion 1903 // available for matching a media_source to a node. 1904 1905 typedef map<port_id, NodeRef*> port_ref_map; 1906 port_ref_map* initialNodes = m_existingNodesInit ? 0 : new port_ref_map; 1907 1908 bool refsCreated = false; 1909 1910 for(int32 n = 0; n < count; ++n) { 1911 // fetch ID of next node 1912 int32 id; 1913 err = message->FindInt32("media_node_id", n, &id); 1914 if(err < B_OK) { 1915 PRINT(( 1916 "* NodeManager::_handleNodesCreated(): FindInt32() failed:\n" 1917 " %s", strerror(err))); 1918 continue; 1919 } 1920 1921 // look up the node 1922 media_node node; 1923 err = roster->GetNodeFor(id, &node); 1924 if(err < B_OK) { 1925 PRINT(( 1926 "* NodeManager::_handleNodesCreated(): roster->GetNodeFor(%ld) failed:\n" 1927 " %s\n", 1928 id, strerror(err))); 1929 continue; 1930 } 1931 1932 // look for an existing NodeRef; if not found, create one: 1933 NodeRef* ref = 0; 1934 if(getNodeRef(node.node, &ref) < B_OK) { 1935 // create one 1936 ref = _addRefFor( 1937 node, 1938 _userFlagsForKind(node.kind), // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99 1939 _implFlagsForKind(node.kind) | NodeRef::_CREATE_NOTIFIED); 1940 1941 refsCreated = true; 1942 1943 // // [e.moon 7nov99] call hook 1944 // nodeCreated(ref); 1945 1946 } else { 1947 // PRINT(( 1948 // "* NodeManager::_handleNodesCreated():\n" 1949 // " found existing ref for '%s' (%ld)\n", 1950 // ref->name(), id)); 1951 1952 1953 // set _CREATE_NOTIFIED to prevent notification from being passed on 1954 // twice [e.moon 11oct99] 1955 if(!(ref->m_implFlags & NodeRef::_CREATE_NOTIFIED)) { 1956 ref->m_implFlags |= NodeRef::_CREATE_NOTIFIED; 1957 refsCreated = true; 1958 } 1959 1960 // release the (duplicate) media_node reference 1961 err = roster->ReleaseNode(node); 1962 if(err < B_OK) { 1963 PRINT(( 1964 "* NodeManager::_handleNodesCreated(): roster->ReleaseNode(%ld) failed:\n" 1965 " %s\n", 1966 id, strerror(err))); 1967 } 1968 } 1969 1970 // add to the 'initial nodes' set if necessary 1971 // [e.moon 13oct99] PPC-friendly 1972 if(initialNodes) 1973 initialNodes->insert( 1974 port_ref_map::value_type( 1975 node.port, ref)); 1976 } 1977 1978 if(initialNodes) { 1979 // populate current connections from each node in the set 1980 // PRINT(( 1981 // "* NodeManager::_handleNodesCreated(): POPULATING CONNECTIONS (%ld)\n", 1982 // initialNodes->size())); 1983 1984 for(port_ref_map::const_iterator itDest = initialNodes->begin(); 1985 itDest != initialNodes->end(); ++itDest) { 1986 1987 // walk each connected input for this node; find corresponding 1988 // output & fill in a new Connection instance. 1989 1990 NodeRef* destRef = (*itDest).second; 1991 ASSERT(destRef); 1992 if(!(destRef->kind() & B_BUFFER_CONSUMER)) 1993 // no inputs 1994 continue; 1995 1996 vector<media_input> inputs; 1997 err = destRef->getConnectedInputs(inputs); 1998 1999 // +++++ FAILED ON STARTUP [e.moon 28sep99]; haven't reproduced yet 2000 // [21oct99] failed again 2001 //ASSERT(err == B_OK); 2002 if(err < B_OK) { 2003 PRINT(( 2004 "!!! NodeManager::_handleNodesCreated():\n" 2005 " NodeRef('%s')::getConnectedInputs() failed:\n" 2006 " %s\n", 2007 destRef->name(), strerror(err))); 2008 2009 continue; 2010 } 2011 2012 2013 // PRINT((" - %s: %ld inputs\n", destRef->name(), inputs.size())); 2014 2015 for(vector<media_input>::const_iterator itInput = inputs.begin(); 2016 itInput != inputs.end(); ++itInput) { 2017 2018 // look for a matching source node by port ID: 2019 const media_input& input = *itInput; 2020 port_ref_map::const_iterator itSource = initialNodes->find( 2021 input.source.port); 2022 2023 if(itSource == initialNodes->end()) { 2024 // source not found! 2025 PRINT(( 2026 "* NodeManager::_handleNodesCreated():\n" 2027 " Building initial Connection set: couldn't find source node\n" 2028 " connected to input '%s' of '%s' (source port %d).\n", 2029 input.name, destRef->name(), input.source.port)); 2030 continue; 2031 } 2032 2033 // found it; fetch matching output 2034 NodeRef* sourceRef = (*itSource).second; 2035 ASSERT(sourceRef); 2036 media_output output; 2037 err = sourceRef->findOutput(input.source, &output); 2038 if(err < B_OK) { 2039 PRINT(( 2040 "* NodeManager::_handleNodesCreated():\n" 2041 " Building initial Connection set: couldn't find output\n" 2042 " in node '%s' connected to input '%s' of '%s'.\n", 2043 sourceRef->name(), 2044 input.name, destRef->name())); 2045 continue; 2046 } 2047 2048 // sanity check 2049 // ASSERT(input.source == output.source); 2050 // ASSERT(input.destination == output.destination); 2051 // diagnostics [e.moon 11jan00] 2052 if(input.source != output.source || 2053 input.destination != output.destination) { 2054 PRINT(( 2055 "!!! NodeManager::_handleNodesCreated():\n" 2056 " input/output mismatch for connection\n" 2057 " '%s' (%s) -> '%s' (%s)\n" 2058 " input.source: port %ld, ID %ld\n" 2059 " output.source: port %ld, ID %ld\n" 2060 " input.destination: port %ld, ID %ld\n" 2061 " output.destination: port %ld, ID %ld\n\n", 2062 sourceRef->name(), output.name, 2063 destRef->name(), input.name, 2064 input.source.port, input.source.id, 2065 output.source.port, output.source.id, 2066 input.destination.port, input.destination.id, 2067 output.destination.port, output.destination.id)); 2068 continue; 2069 } 2070 2071 // instantiate & add connection 2072 2073 uint32 flags = 0; 2074 2075 // 22sep99: lock audio-mixer connection 2076 if( 2077 sourceRef == m_audioMixerNode && 2078 destRef == m_audioOutputNode) 2079 flags |= Connection::LOCKED; 2080 2081 Connection* con = new Connection( 2082 m_nextConID++, 2083 output.node, 2084 output.source, 2085 output.name, 2086 input.node, 2087 input.destination, 2088 input.name, 2089 input.format, 2090 flags); 2091 2092 _addConnection(con); 2093 2094 // // [e.moon 7nov99] call hook 2095 // connectionMade(con); 2096 2097 // PRINT(( 2098 // "* NodeManager::_handleNodesCreated(): Found initial connection:\n" 2099 // " %s:%s -> %s:%s\n", 2100 // sourceRef->name(), con->outputName(), 2101 // destRef->name(), con->inputName())); 2102 2103 } // for(vector<media_input> ... 2104 2105 } // for(port_ref_map ... 2106 2107 // mark the ordeal as over & done with 2108 m_existingNodesInit = true; 2109 // clean up 2110 delete initialNodes; 2111 } 2112 2113 // don't relay message if no new create notifications were received [e.moon 11oct99] 2114 return refsCreated ? B_OK : B_ERROR; 2115 } 2116 2117 inline void NodeManager::_handleNodesDeleted( 2118 BMessage* message) { 2119 ASSERT(IsLocked()); 2120 2121 D_METHOD(( 2122 "NodeManager::_handleNodesDeleted()\n")); 2123 2124 // walk the list of deleted nodes, removing & cleaning up refs 2125 // (and any straggler connections) 2126 2127 type_code type; 2128 int32 count; 2129 status_t err = message->GetInfo("media_node_id", &type, &count); 2130 if(err < B_OK) { 2131 PRINT(( 2132 "* NodeManager::_handleNodesDeleted(): GetInfo() failed:\n" 2133 " %s\n", 2134 strerror(err))); 2135 return; 2136 } 2137 if(!count) 2138 return; 2139 2140 for(int32 n = 0; n < count; n++) { 2141 2142 int32 id; 2143 err = message->FindInt32("media_node_id", n, &id); 2144 if(err < B_OK) { 2145 PRINT(( 2146 "* NodeManager::_handleNodesDeleted(): FindInt32() failed\n" 2147 " %s\n", 2148 strerror(err))); 2149 continue; 2150 } 2151 2152 // fetch ref 2153 NodeRef* ref; 2154 err = getNodeRef(id, &ref); 2155 if(err < B_OK) { 2156 PRINT(( 2157 "* NodeManager::_handleNodesDeleted(): getNodeRef(%ld) failed\n" 2158 " %s\n", 2159 id, strerror(err))); 2160 continue; 2161 } 2162 2163 // find & remove any 'stuck' connections; notify any observers 2164 // that the connections have been removed 2165 vector<Connection> stuckConnections; 2166 ref->getInputConnections(stuckConnections); 2167 ref->getOutputConnections(stuckConnections); 2168 2169 BMessage message(B_MEDIA_CONNECTION_BROKEN); 2170 2171 for(uint32 n = 0; n < stuckConnections.size(); ++n) { 2172 Connection& c = stuckConnections[n]; 2173 2174 // generate a complete B_MEDIA_CONNECTION_BROKEN message 2175 // +++++ the message format may be extended in the future -- ick 2176 2177 message.AddData("source", B_RAW_TYPE, &c.source(), sizeof(media_source)); 2178 message.AddData("destination", B_RAW_TYPE, &c.destination(), sizeof(media_destination)); 2179 message.AddInt32(_connectionField, c.id()); 2180 message.AddInt32(_sourceNodeField, c.sourceNode()); 2181 message.AddInt32(_destNodeField, c.destinationNode()); 2182 2183 _removeConnection(c); 2184 } 2185 2186 // +++++ don't notify if no stuck connections were found 2187 notify(&message); 2188 2189 // ungroup if necessary 2190 if(ref->m_group) { 2191 ASSERT(!ref->isReleased()); 2192 ref->m_group->removeNode(ref); 2193 } 2194 2195 // [e.moon 23oct99] mark the node released! 2196 ref->m_nodeReleased = true; 2197 2198 // // [e.moon 7nov99] call hook 2199 // nodeDeleted(ref); 2200 2201 // release it 2202 ref->release(); 2203 2204 } // for(int32 n ... 2205 } 2206 2207 inline void NodeManager::_handleConnectionMade( 2208 BMessage* message) { 2209 ASSERT(IsLocked()); 2210 D_METHOD(( 2211 "NodeManager::_handleConnectionMade()\n")); 2212 status_t err; 2213 2214 for(int32 n = 0;;++n) { 2215 media_input input; 2216 media_output output; 2217 const void* data; 2218 ssize_t dataSize; 2219 2220 // fetch output 2221 err = message->FindData("output", B_RAW_TYPE, n, &data, &dataSize); 2222 if(err < B_OK) { 2223 if(!n) { 2224 PRINT(( 2225 "* NodeManager::_handleConnectionMade(): no entries in message.\n")); 2226 } 2227 break; 2228 } 2229 if(dataSize < ssize_t(sizeof(media_output))) { 2230 PRINT(( 2231 "* NodeManager::_handleConnectionMade(): not enough data for output.\n")); 2232 break; 2233 } 2234 output = *(media_output*)data; 2235 2236 // fetch input 2237 err = message->FindData("input", B_RAW_TYPE, n, &data, &dataSize); 2238 if(err < B_OK) { 2239 if(!n) { 2240 PRINT(( 2241 "* NodeManager::_handleConnectionMade(): no complete entries in message.\n")); 2242 } 2243 break; 2244 } 2245 if(dataSize < ssize_t(sizeof(media_input))) { 2246 PRINT(( 2247 "* NodeManager::_handleConnectionMade(): not enough data for input.\n")); 2248 break; 2249 } 2250 input = *(media_input*)data; 2251 2252 // look for existing Connection instance 2253 Connection found; 2254 err = findConnection( 2255 output.node.node, 2256 output.source, 2257 &found); 2258 if(err == B_OK) { 2259 PRINT(( 2260 " - existing connection for %s -> %s found\n", 2261 found.outputName(), found.inputName())); 2262 continue; 2263 } 2264 2265 // instantiate & add Connection 2266 Connection* con = new Connection( 2267 m_nextConID++, 2268 output.node, 2269 output.source, 2270 output.name, 2271 input.node, 2272 input.destination, 2273 input.name, 2274 input.format, 2275 0); 2276 2277 _addConnection(con); 2278 } 2279 } 2280 2281 // augments message with source and destination node ID's 2282 inline void NodeManager::_handleConnectionBroken( 2283 BMessage* message) { 2284 2285 D_METHOD(( 2286 "NodeManager::_handleConnectionBroken()\n")); 2287 status_t err; 2288 2289 // walk the listed connections 2290 for(int32 n=0;;n++) { 2291 media_source source; 2292 2293 const void* data; 2294 ssize_t dataSize; 2295 2296 // fetch source 2297 err = message->FindData("source", B_RAW_TYPE, n, &data, &dataSize); 2298 if(err < B_OK) { 2299 if(!n) { 2300 PRINT(( 2301 "* NodeManager::_handleConnectionBroken(): incomplete entry in message.\n")); 2302 } 2303 break; 2304 } 2305 if(dataSize < ssize_t(sizeof(media_source))) { 2306 PRINT(( 2307 "* NodeManager::_handleConnectionBroken(): not enough data for source.\n")); 2308 continue; 2309 } 2310 source = *(media_source*)data; 2311 2312 // look up the connection +++++ SLOW +++++ 2313 Connection con; 2314 err = findConnection(source, &con); 2315 if(err < B_OK) { 2316 PRINT(( 2317 "* NodeManager::_handleConnectionBroken(): connection not found:\n" 2318 " %ld:%ld\n", 2319 source.port, source.id)); 2320 2321 // add empty entry to message 2322 message->AddInt32(_connectionField, 0); 2323 message->AddInt32(_sourceNodeField, 0); 2324 message->AddInt32(_destNodeField, 0); 2325 continue; 2326 } 2327 2328 // add entry to the message 2329 message->AddInt32(_connectionField, con.id()); 2330 message->AddInt32(_sourceNodeField, con.sourceNode()); 2331 message->AddInt32(_destNodeField, con.destinationNode()); 2332 2333 // // [e.moon 7nov99] call hook 2334 // connectionBroken(&con); 2335 2336 // home free; delete the connection 2337 _removeConnection(con); 2338 2339 } // for(int32 n ... 2340 } 2341 2342 inline void 2343 NodeManager::_handleFormatChanged(BMessage *message) 2344 { 2345 D_METHOD(( 2346 "NodeManager::_handleFormatChanged()\n")); 2347 status_t err; 2348 2349 ssize_t dataSize; 2350 2351 // fetch source 2352 media_source* source; 2353 err = message->FindData("be:source", B_RAW_TYPE, (const void**)&source, &dataSize); 2354 if(err < B_OK) { 2355 PRINT(( 2356 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n")); 2357 return; 2358 } 2359 2360 // fetch destination 2361 media_destination* destination; 2362 err = message->FindData("be:destination", B_RAW_TYPE, (const void**)&destination, &dataSize); 2363 if(err < B_OK) { 2364 PRINT(( 2365 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n")); 2366 return; 2367 } 2368 2369 // fetch format 2370 media_format* format; 2371 err = message->FindData("be:format", B_RAW_TYPE, (const void**)&format, &dataSize); 2372 if(err < B_OK) { 2373 PRINT(( 2374 "* NodeManager::_handleFormatChanged(): incomplete entry in message.\n")); 2375 return; 2376 } 2377 2378 // find matching connection 2379 for(con_map::const_iterator it = m_conSourceMap.begin(); 2380 it != m_conSourceMap.end(); ++it) { 2381 if((*it).second->source() == *source) { 2382 if((*it).second->destination() != *destination) { 2383 // connection defunct 2384 return; 2385 } 2386 2387 // found 2388 (*it).second->m_format = *format; 2389 2390 // attach node IDs to message 2391 message->AddInt32(_connectionField, (*it).second->id()); 2392 message->AddInt32(_sourceNodeField, (*it).second->sourceNode()); 2393 message->AddInt32(_destNodeField, (*it).second->destinationNode()); 2394 2395 break; 2396 } 2397 } 2398 } 2399 2400 2401 // return flags appropriate for an external 2402 // node with the given 'kind' 2403 2404 inline uint32 NodeManager::_userFlagsForKind( 2405 uint32 kind) { 2406 2407 uint32 f = 0; 2408 if( 2409 // kind & B_TIME_SOURCE || 2410 kind & B_PHYSICAL_OUTPUT 2411 // || kind & B_SYSTEM_MIXER [now in initCommonNodes() e.moon 17nov99] 2412 ) 2413 f |= (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL); 2414 2415 // // [28sep99 e.moon] physical inputs may not be stopped for now; at 2416 // // least one sound input node (for emu10k) stops working when requested 2417 // // to stop. 2418 // // +++++ should this logic be in initCommonNodes()? 2419 // if( 2420 // kind & B_PHYSICAL_INPUT) 2421 // f |= NodeRef::NO_STOP; 2422 2423 return f; 2424 } 2425 2426 inline uint32 NodeManager::_implFlagsForKind( 2427 uint32 kind) { 2428 2429 return 0; 2430 } 2431 2432 // [e.moon 28sep99] latency updating 2433 // These methods must set the recording-mode delay for 2434 // any B_RECORDING nodes they handle. 2435 2436 // +++++ abstract to 'for each' and 'for each from' 2437 // methods (template or callback?) 2438 2439 2440 // refresh cached latency for every node in the given group 2441 // (or all nodes if no group given.) 2442 2443 inline void NodeManager::_updateLatencies( 2444 NodeGroup* group) { 2445 2446 ASSERT(IsLocked()); 2447 if(group) { 2448 ASSERT(group->isLocked()); 2449 } 2450 2451 if(group) { 2452 for(NodeGroup::node_set::iterator it = group->m_nodes.begin(); 2453 it != group->m_nodes.end(); ++it) { 2454 2455 (*it)->_updateLatency(); 2456 } 2457 } 2458 else { 2459 for(node_ref_map::iterator it = m_nodeRefMap.begin(); 2460 it != m_nodeRefMap.end(); ++it) { 2461 2462 (*it).second->_updateLatency(); 2463 } 2464 } 2465 } 2466 2467 // refresh cached latency for every node attached to 2468 // AND INCLUDING the given origin node. 2469 // if 'recurse' is true, affects indirectly attached 2470 // nodes as well. 2471 2472 2473 inline void NodeManager::_updateLatenciesFrom( 2474 NodeRef* origin, 2475 bool recurse) { 2476 2477 ASSERT(IsLocked()); 2478 2479 // PRINT(("### NodeManager::_updateLatenciesFrom()\n")); 2480 2481 origin->lock(); 2482 origin->_updateLatency(); 2483 origin->unlock(); 2484 2485 _lockAllGroups(); // [e.moon 13oct99] 2486 2487 _for_each_state st; 2488 _do_for_each_connected( 2489 this, 2490 origin, 2491 0, // all groups 2492 recurse, 2493 mem_fun(&NodeRef::_updateLatency), 2494 &st); 2495 2496 _unlockAllGroups(); // [e.moon 13oct99] 2497 } 2498 2499 // a bit of unpleasantness [e.moon 13oct99] 2500 void NodeManager::_lockAllGroups() { 2501 2502 ASSERT(IsLocked()); 2503 for(node_group_set::iterator it = m_nodeGroupSet.begin(); 2504 it != m_nodeGroupSet.end(); ++it) { 2505 (*it)->lock(); 2506 } 2507 } 2508 2509 void NodeManager::_unlockAllGroups() { 2510 ASSERT(IsLocked()); 2511 for(node_group_set::iterator it = m_nodeGroupSet.begin(); 2512 it != m_nodeGroupSet.end(); ++it) { 2513 (*it)->unlock(); 2514 } 2515 } 2516 2517 2518 // END -- NodeManager.cpp -- 2519