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