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