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