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