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