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