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