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 // NodeRef.cpp 33 34 #include "NodeRef.h" 35 36 #include "Connection.h" 37 #include "NodeGroup.h" 38 //#include "NodeGroup_transport_thread.h" 39 #include "NodeManager.h" 40 #include "NodeSyncThread.h" 41 42 #include "AddOnHost.h" 43 44 #include <Entry.h> 45 #include <MediaRoster.h> 46 #include <TimeSource.h> 47 48 #include <algorithm> 49 #include <functional> 50 #include <iterator> 51 #include <stdexcept> 52 53 #include "functional_tools.h" 54 #include "node_manager_impl.h" 55 #include "SoundUtils.h" 56 57 // -------------------------------------------------------- // 58 59 using namespace std; 60 61 __USE_CORTEX_NAMESPACE 62 63 #define D_METHOD(x) //PRINT (x) 64 #define D_MESSAGE(x) //PRINT (x) 65 #define D_ROSTER(x) //PRINT (x) 66 #define D_LOCK(x) //PRINT (x) 67 68 // -------------------------------------------------------- // 69 // addon_hint 70 // 71 // Contains information that can be used to reconstruct this 72 // node later on. 73 // -------------------------------------------------------- // 74 75 // [e.moon 29sep99] added 'file' 76 77 struct NodeRef::addon_hint { 78 79 addon_hint( 80 const dormant_node_info* _dormantInfo, 81 const entry_ref* _file=0) : 82 dormantInfo(*_dormantInfo), 83 file(_file ? new entry_ref(*_file) : 0) {} 84 85 ~addon_hint() { 86 if(file) delete file; 87 } 88 89 void setFile( 90 const entry_ref* _file) { 91 ASSERT(_file); 92 if(file) delete file; 93 file = new entry_ref(*_file); 94 } 95 96 dormant_node_info dormantInfo; 97 entry_ref* file; 98 }; 99 100 // -------------------------------------------------------- // 101 // *** ctor/dtor 102 // -------------------------------------------------------- // 103 104 // free the node (this call will result in the eventual 105 // deletion of the object.) 106 107 status_t NodeRef::release() { 108 109 // release the node, if possible: 110 status_t err = releaseNode(); 111 112 // hand off to parent release() implementation 113 status_t parentErr = _inherited::release(); 114 return (parentErr < B_OK) ? parentErr : err; 115 } 116 117 NodeRef::~NodeRef() { 118 D_METHOD(("~NodeRef[%s]\n", name())); 119 Autolock _l(m_manager); 120 121 // remove from NodeManager 122 m_manager->_removeRef(id()); 123 124 // [14oct99 e.moon] kill position-report thread if necessary 125 if(m_positionThread) 126 _stopPositionThread(); 127 128 if(m_addonHint) { 129 delete m_addonHint; 130 m_addonHint = 0; 131 } 132 133 // close Media Roster connection [e.moon 11oct99] 134 BMediaRoster* r = BMediaRoster::Roster(); 135 if(m_watching) { 136 r->StopWatching( 137 BMessenger(this), 138 node(), 139 B_MEDIA_WILDCARD); 140 } 141 } 142 143 // -------------------------------------------------------- // 144 // *** const accessors 145 // -------------------------------------------------------- // 146 147 // [e.moon 13oct99] moved to header 148 149 //inline const media_node& NodeRef::node() const { return m_info.node; } 150 //inline uint32 NodeRef::kind() const { return m_info.node.kind; } 151 //inline const live_node_info& NodeRef::nodeInfo() const { return m_info; } 152 //inline media_node_id NodeRef::id() const { return m_info.node.node; } 153 //inline const char* NodeRef::name() const { return m_info.name; } 154 155 // -------------------------------------------------------- // 156 // *** member access 157 // -------------------------------------------------------- // 158 159 // turn cycle mode (looping) on or off 160 161 void NodeRef::setCycling( 162 bool cycle) { 163 Autolock _l(this); 164 165 D_METHOD(( 166 "NodeRef::setCycling(%s)\n", 167 cycle ? "true" : "false")); 168 169 if(cycle == m_cycle) 170 return; 171 172 m_cycle = cycle; 173 174 if(m_group) { 175 m_group->_refCycleChanged(this); 176 177 // +++++ if running, get started... 178 } 179 180 // notify 181 BMessage m(M_CYCLING_CHANGED); 182 m.AddBool("cycling", cycle); 183 notify(&m); 184 } 185 186 bool NodeRef::isCycling() const { 187 return m_cycle; 188 } 189 190 191 // is the node running? 192 193 bool NodeRef::isRunning() const { 194 return m_running; 195 } 196 197 // was the node created via NodeManager::instantiate()? 198 bool NodeRef::isInternal() const { 199 return m_implFlags & _INTERNAL; 200 } 201 202 203 // fetch the group; may return 0 if the node has no connections 204 NodeGroup* NodeRef::group() const { 205 Autolock _l(this); 206 return m_group; 207 } 208 209 // flag access 210 uint32 NodeRef::flags() const { 211 Autolock _l(this); 212 return m_flags; 213 } 214 215 void NodeRef::setFlags( 216 uint32 flags) { 217 Autolock _l(this); 218 m_flags = flags; 219 } 220 221 //// has this reference been released? 222 //bool NodeRef::isReleased() const { 223 // // no lock necessary for bool access -- right? +++++ 224 // return m_released; 225 //} 226 // 227 228 // [e.moon 29sep99] 229 // access addon-hint info 230 // - returns B_BAD_VALUE if not an add-on node created by this NodeManager 231 232 status_t NodeRef::getDormantNodeInfo( 233 dormant_node_info* outInfo) { 234 235 if(!m_addonHint) 236 return B_BAD_VALUE; 237 238 *outInfo = m_addonHint->dormantInfo; 239 return B_OK; 240 } 241 242 // [e.moon 29sep99] 243 // access file being played 244 // - returns B_BAD_VALUE if not an add-on node created by this NodeManager, 245 // or if the node has no associated file 246 247 status_t NodeRef::getFile( 248 entry_ref* outFile) { 249 250 Autolock _l(this); 251 252 if(!m_addonHint || !m_addonHint->file) 253 return B_BAD_VALUE; 254 255 *outFile = *(m_addonHint->file); 256 return B_OK; 257 } 258 259 // [e.moon 8dec99] 260 // set file to play 261 262 status_t NodeRef::setFile( 263 const entry_ref& file, 264 bigtime_t* outDuration) { 265 266 Autolock _l(this); 267 268 bigtime_t dur; 269 status_t err = m_manager->roster->SetRefFor( 270 node(), 271 file, 272 false, 273 &dur); 274 if(err == B_OK) { 275 if(outDuration) 276 *outDuration = dur; 277 if(m_addonHint) 278 m_addonHint->setFile(&file); 279 } 280 281 return err; 282 } 283 284 // [e.moon 23oct99] 285 // returns true if the media_node has been released (call releaseNode() to 286 // make this happen.) 287 288 bool NodeRef::isNodeReleased() const { 289 return m_nodeReleased; 290 } 291 292 // -------------------------------------------------------- // 293 // *** run-mode operations 294 // -------------------------------------------------------- // 295 296 void NodeRef::setRunMode( 297 uint32 runMode, 298 bigtime_t delay) { 299 Autolock _l(this); 300 301 ASSERT(runMode <= BMediaNode::B_RECORDING); 302 m_runMode = runMode; 303 if(runMode == BMediaNode::B_RECORDING) 304 m_recordingDelay = delay; 305 306 // send notification to all observers 307 BMessage m(M_RUN_MODE_CHANGED); 308 m.AddInt32("nodeID", id()); 309 m.AddInt32("runMode", runMode); 310 311 if(runMode == BMediaNode::B_RECORDING && m_recordingDelay != 0) 312 m.AddInt64("delay", m_recordingDelay); 313 314 notify(&m); 315 316 // update real run mode 317 if(m_group) 318 _setRunMode(m_group->runMode(), m_recordingDelay); 319 } 320 321 uint32 NodeRef::runMode() const { 322 Autolock _l(this); 323 return m_runMode; 324 } 325 326 bigtime_t NodeRef::recordingDelay() const { 327 Autolock _l(this); 328 return m_recordingDelay; 329 } 330 331 // calculates the minimum amount of delay needed for 332 // B_RECORDING mode 333 // +++++ 15sep99: returns biggest_output_buffer_duration * 2 334 // +++++ 28sep99: adds downstream latency 335 336 bigtime_t NodeRef::calculateRecordingModeDelay() { 337 PRINT(( 338 "NodeRef::calculateRecordingModeDelay()\n")); 339 status_t err; 340 341 bigtime_t maxBufferDur = 0LL; 342 343 vector<Connection> outputConnections; 344 err = getOutputConnections(outputConnections); 345 for( 346 vector<Connection>::iterator it = outputConnections.begin(); 347 it != outputConnections.end(); ++it) { 348 349 bigtime_t bufferDur = buffer_duration((*it).format().u.raw_audio); 350 if(bufferDur > maxBufferDur) 351 maxBufferDur = bufferDur; 352 } 353 354 bigtime_t latency = 0LL; 355 err = m_manager->roster->GetLatencyFor( 356 node(), &latency); 357 358 PRINT(( 359 " %Ld\n", latency)); 360 361 return latency; // +++++ stab in the dark 28sep99 362 // return maxBufferDur + latency; 363 } 364 365 // -------------------------------------------------------- // 366 // *** connection access 367 // -------------------------------------------------------- // 368 369 // connection access: vector versions 370 371 status_t NodeRef::getInputConnections( 372 vector<Connection>& ioConnections, 373 media_type filterType) const { 374 Autolock _l(this); 375 376 NodeManager::con_map::iterator it, itEnd; 377 it = m_manager->m_conDestinationMap.lower_bound(m_info.node.node); 378 itEnd = m_manager->m_conDestinationMap.upper_bound(m_info.node.node); 379 380 for(; it != itEnd; ++it) { 381 if(filterType == B_MEDIA_UNKNOWN_TYPE || 382 (*it).second->format().type == filterType) { 383 384 ioConnections.push_back(*((*it).second)); 385 } 386 } 387 388 return B_OK; 389 } 390 391 392 status_t NodeRef::getOutputConnections( 393 vector<Connection>& ioConnections, 394 media_type filterType) const { 395 Autolock _l(this); 396 397 NodeManager::con_map::iterator it, itEnd; 398 it = m_manager->m_conSourceMap.lower_bound(m_info.node.node); 399 itEnd = m_manager->m_conSourceMap.upper_bound(m_info.node.node); 400 401 for(; it != itEnd; ++it) { 402 if(filterType == B_MEDIA_UNKNOWN_TYPE || 403 (*it).second->format().type == filterType) { 404 405 ioConnections.push_back(*((*it).second)); 406 } 407 } 408 409 return B_OK; 410 } 411 412 // connection access: flat array versions 413 414 status_t NodeRef::getInputConnections( 415 Connection* outConnections, 416 int32 maxConnections, 417 int32* outNumConnections, 418 media_type filterType) const { 419 Autolock _l(this); 420 421 NodeManager::con_map::iterator it, itEnd; 422 it = m_manager->m_conDestinationMap.lower_bound(m_info.node.node); 423 itEnd = m_manager->m_conDestinationMap.upper_bound(m_info.node.node); 424 425 int32 count = 0; 426 427 for(; it != itEnd && count < maxConnections; ++it) { 428 if(filterType == B_MEDIA_UNKNOWN_TYPE || 429 (*it).second->format().type == filterType) { 430 431 outConnections[count++] = *((*it).second); 432 } 433 } 434 435 *outNumConnections = count; 436 437 return B_OK; 438 } 439 440 status_t NodeRef::getOutputConnections( 441 Connection* outConnections, 442 int32 maxConnections, 443 int32* outNumConnections, 444 media_type filterType) const { 445 Autolock _l(this); 446 447 NodeManager::con_map::iterator it, itEnd; 448 it = m_manager->m_conSourceMap.lower_bound(m_info.node.node); 449 itEnd = m_manager->m_conSourceMap.upper_bound(m_info.node.node); 450 451 int32 count = 0; 452 453 for(; it != itEnd && count < maxConnections; ++it) { 454 if(filterType == B_MEDIA_UNKNOWN_TYPE || 455 (*it).second->format().type == filterType) { 456 457 outConnections[count++] = *((*it).second); 458 } 459 } 460 461 *outNumConnections = count; 462 463 return B_OK; 464 } 465 466 // -------------------------------------------------------- // 467 // *** position reporting/listening 468 // -------------------------------------------------------- // 469 470 bool NodeRef::positionReportsEnabled() const { 471 return m_positionReportsEnabled; 472 } 473 474 // start thread if necessary 475 void NodeRef::enablePositionReports() { 476 Autolock _l(this); 477 478 if(m_flags & NO_POSITION_REPORTING) 479 return; 480 481 if(m_positionReportsEnabled) 482 return; 483 484 m_positionReportsEnabled = true; 485 if(m_running) { 486 // start the thread 487 _startPositionThread(); 488 } 489 } 490 491 // stop thread if necessary 492 void NodeRef::disablePositionReports() { 493 Autolock _l(this); 494 495 if(!m_positionReportsEnabled) 496 return; 497 498 m_positionReportsEnabled = false; 499 if(m_running) { 500 // shut down the thread 501 _stopPositionThread(); 502 } 503 } 504 505 // Fetch the approximate current position: 506 // Returns the last reported position, and the 507 // performance time at which that position was reached. If the 508 // transport has never been started, the start position and 509 // a performance time of 0 will be returned. If position updating 510 // isn't currently enabled, returns B_NOT_ALLOWED. 511 512 status_t NodeRef::getLastPosition( 513 bigtime_t* outPosition, 514 bigtime_t* outPerfTime) const { 515 516 Autolock _l(this); 517 518 if(!m_positionReportsEnabled) 519 return B_NOT_ALLOWED; 520 521 *outPosition = m_lastPosition; 522 *outPerfTime = m_tpLastPositionUpdate; 523 return B_OK; 524 } 525 526 // Subscribe to regular position reports: 527 // Position reporting isn't rolled into the regular IObservable 528 // interface because a large number of messages are generated 529 // (the frequency can be changed; see below.) 530 531 status_t NodeRef::addPositionObserver( 532 BHandler* handler) { 533 ASSERT(handler); 534 535 // try to create messenger 536 status_t error; 537 BMessenger m(handler, NULL, &error); 538 if(error < B_OK) { 539 PRINT(( 540 "* NodeRef::addPositionListener(): BMessenger() failed:\n" 541 " %s\n" 542 " handler %p\n", 543 strerror(error), handler)); 544 return error; 545 } 546 547 // add to the invoker 548 Autolock _l(this); 549 m_positionInvoker.AddTarget(handler); 550 551 // enable position updates: 552 if(!m_positionReportsEnabled) 553 enablePositionReports(); 554 555 return B_OK; 556 } 557 558 status_t NodeRef::removePositionObserver( 559 BHandler* handler) { 560 ASSERT(handler); 561 562 Autolock _l(this); 563 564 // look for listener 565 int32 index = m_positionInvoker.IndexOfTarget(handler); 566 if(index == -1) 567 return B_ERROR; 568 569 // remove it 570 m_positionInvoker.RemoveTarget(index); 571 572 // last observer removed? kill thread. [e.moon 12oct99] 573 if(m_positionReportsEnabled && !m_positionInvoker.CountTargets()) 574 disablePositionReports(); 575 576 return B_OK; 577 } 578 579 // Set how often position updates will be sent: 580 // Realistically, period should be > 10000 or so. 581 582 status_t NodeRef::setPositionUpdatePeriod( 583 bigtime_t period) { 584 585 Autolock _l(this); 586 if(period < 1000LL) 587 return B_BAD_VALUE; 588 m_positionUpdatePeriod = period; 589 return B_OK; 590 } 591 592 bigtime_t NodeRef::positionUpdatePeriod() const{ 593 Autolock _l(this); 594 return m_positionUpdatePeriod; 595 } 596 597 // -------------------------------------------------------- // 598 // *** BMediaRoster wrappers & convenience methods 599 // -------------------------------------------------------- // 600 601 // release the media node 602 // (if allowed, will trigger the release/deletion of this object) 603 status_t NodeRef::releaseNode() { 604 605 D_METHOD(( 606 "NodeRef[%s]::releaseNode()\n", name())); 607 status_t err; 608 609 Autolock _l(m_manager); 610 611 if(isReleased() || m_nodeReleased) 612 return B_NOT_ALLOWED; 613 614 if(m_group) 615 m_group->removeNode(this); 616 617 // kill off sync thread 618 if(m_positionThread) { 619 delete m_positionThread; 620 m_positionThread = 0; 621 } 622 623 if(m_implFlags & _INTERNAL) { 624 625 // tear down all connections if the node was created by 626 // NodeManager 627 vector<Connection> c_set; 628 getInputConnections(c_set); 629 getOutputConnections(c_set); 630 631 // [e.moon 13oct99] making PPC compiler happy 632 // for_each( 633 // c_set.begin(), 634 // c_set.end(), 635 // bound_method( 636 // *m_manager, 637 // &NodeManager::disconnect 638 // ) 639 // ); 640 641 for(vector<Connection>::iterator it = c_set.begin(); 642 it != c_set.end(); ++it) { 643 err = m_manager->disconnect(*it); 644 if(err < B_OK) { 645 PRINT(( 646 "! NodeRef('%s')::releaseNode():\n" 647 " NodeManager::disconnect('%s'->'%s') failed:\n" 648 " %s\n", 649 name(), 650 (*it).outputName(), (*it).inputName(), 651 strerror(err))); 652 } 653 } 654 655 // +++++ ensure that the connections were really broken? 656 } 657 658 err = B_OK; 659 if(!(m_implFlags & _NO_RELEASE)) { 660 661 // PRINT(( 662 // "### releasing node %ld\n", 663 // id())); 664 // 665 // free the node 666 D_ROSTER(("# roster->ReleaseNode(%ld)\n", m_info.node.node)); 667 err = BMediaRoster::Roster()->ReleaseNode( 668 m_info.node); 669 670 if(err < B_OK) { 671 PRINT(( 672 "!!! ReleaseNode(%ld) failed:\n" 673 " %s\n", 674 m_info.node.node, 675 strerror(err))); 676 } 677 678 if( 679 (m_implFlags & _INTERNAL) && 680 m_manager->m_useAddOnHost) { 681 682 // ask add-on host to release the node 683 err = AddOnHost::ReleaseInternalNode(m_info); 684 if(err < B_OK) { 685 PRINT(( 686 "!!! AddOnHost::ReleaseInternalNode(%ld) failed:\n" 687 " %s\n", 688 m_info.node.node, 689 strerror(err))); 690 } 691 } 692 } 693 else { 694 // PRINT(("- not releasing node\n")); 695 } 696 697 m_nodeReleased = true; 698 return err; 699 } 700 701 702 // calculate total (internal + downstream) latency for this node 703 704 status_t NodeRef::totalLatency( 705 bigtime_t* outLatency) const { 706 707 return BMediaRoster::Roster()->GetLatencyFor( 708 m_info.node, 709 outLatency); 710 } 711 712 // retrieve input/output matching the given destination/source. 713 // returns B_MEDIA_BAD_[SOURCE | DESTINATION] if the destination 714 // or source don't correspond to this node. 715 716 class match_input_destination { public: 717 const media_destination& dest; 718 match_input_destination(const media_destination& _dest) : dest(_dest) {} 719 bool operator()(const media_input& input) const { 720 return input.destination == dest; 721 } 722 }; 723 724 class match_output_source { public: 725 const media_source& source; 726 match_output_source(const media_source& _source) : source(_source) {} 727 bool operator()(const media_output& output) const { 728 return output.source == source; 729 } 730 }; 731 732 status_t NodeRef::findInput( 733 const media_destination& forDestination, 734 media_input* outInput) const { 735 736 status_t err; 737 738 vector<media_input> inputs; 739 vector<media_input>::const_iterator it; 740 inputs.reserve(32); 741 742 // check free inputs 743 err = getFreeInputs(inputs); 744 if(err < B_OK) 745 return err; 746 747 it = find_if( 748 inputs.begin(), inputs.end(), 749 match_input_destination(forDestination)); 750 751 if(it != inputs.end()) { 752 *outInput = *it; 753 return B_OK; 754 } 755 756 // check connected inputs 757 inputs.clear(); 758 err = getConnectedInputs(inputs); 759 if(err < B_OK) 760 return err; 761 762 it = find_if( 763 inputs.begin(), inputs.end(), 764 match_input_destination(forDestination)); 765 766 if(it != inputs.end()) { 767 *outInput = *it; 768 return B_OK; 769 } 770 return B_MEDIA_BAD_DESTINATION; 771 } 772 773 status_t NodeRef::findOutput( 774 const media_source& forSource, 775 media_output* outOutput) const { 776 777 status_t err; 778 779 vector<media_output> outputs; 780 vector<media_output>::const_iterator it; 781 outputs.reserve(32); 782 783 // check free outputs 784 err = getFreeOutputs(outputs); 785 if(err < B_OK) 786 return err; 787 788 it = find_if( 789 outputs.begin(), outputs.end(), 790 match_output_source(forSource)); 791 792 if(it != outputs.end()) { 793 *outOutput = *it; 794 return B_OK; 795 } 796 797 // check connected outputs 798 outputs.clear(); 799 err = getConnectedOutputs(outputs); 800 if(err < B_OK) 801 return err; 802 803 it = find_if( 804 outputs.begin(), outputs.end(), 805 match_output_source(forSource)); 806 807 if(it != outputs.end()) { 808 *outOutput = *it; 809 return B_OK; 810 } 811 812 return B_MEDIA_BAD_SOURCE; 813 } 814 815 816 // endpoint matching (given name and/or format as 'hints') 817 818 template <class T> 819 class match_endpoint_name_format : public unary_function<T, bool> { 820 public: 821 const char* name; 822 const media_format* format; 823 824 match_endpoint_name_format(const char* _name, const media_format* _format) : 825 name(_name), format(_format) {} 826 bool operator()(const T& endpoint) const { 827 // test name, if given 828 if(name && strcmp(endpoint.name, name) != 0) 829 return false; 830 // test format, if given 831 media_format* f1 = const_cast<media_format*>(format); 832 media_format* f2 = const_cast<media_format*>(&endpoint.format); 833 if(format && !f1->Matches(f2)) 834 return false; 835 return true; 836 } 837 }; 838 839 template <class T> 840 class match_endpoint_name_type : public unary_function<T, bool> { 841 public: 842 const char* name; 843 media_type type; 844 845 match_endpoint_name_type(const char* _name, media_type _type) : 846 name(_name), type(_type) {} 847 bool operator()(const T& endpoint) const { 848 // test name, if given 849 if(name && strcmp(endpoint.name, name) != 0) 850 return false; 851 // test type, if given 852 if(type != B_MEDIA_UNKNOWN_TYPE && 853 type != endpoint.format.type) 854 return false; 855 856 return true; 857 } 858 }; 859 860 template <class T> 861 class match_endpoint_type : public unary_function<T, bool> { 862 public: 863 media_type type; 864 865 match_endpoint_type(media_type _type) : 866 type(_type) {} 867 bool operator()(const T& endpoint) const { 868 // test type, if given 869 if(type != B_MEDIA_UNKNOWN_TYPE && 870 type != endpoint.format.type) 871 return false; 872 873 return true; 874 } 875 }; 876 877 status_t NodeRef::findFreeInput( 878 media_input* outInput, 879 const media_format* format /*=0*/, 880 const char* name /*=0*/) const { 881 882 status_t err; 883 884 vector<media_input> inputs; 885 vector<media_input>::const_iterator it; 886 inputs.reserve(32); 887 888 err = getFreeInputs(inputs); 889 if(err < B_OK) 890 return err; 891 892 it = find_if( 893 inputs.begin(), 894 inputs.end(), 895 match_endpoint_name_format<media_input>(name, format)); 896 897 if(it != inputs.end()) { 898 *outInput = *it; 899 return B_OK; 900 } 901 return B_ERROR; 902 } 903 904 status_t NodeRef::findFreeInput( 905 media_input* outInput, 906 media_type type /*=B_MEDIA_UNKNOWN_TYPE*/, 907 const char* name /*=0*/) const { 908 909 status_t err; 910 911 vector<media_input> inputs; 912 vector<media_input>::const_iterator it; 913 inputs.reserve(32); 914 915 err = getFreeInputs(inputs); 916 if(err < B_OK) 917 return err; 918 919 it = find_if( 920 inputs.begin(), 921 inputs.end(), 922 match_endpoint_name_type<media_input>(name, type)); 923 if(it != inputs.end()) { 924 *outInput = *it; 925 return B_OK; 926 } 927 return B_ERROR; 928 } 929 930 status_t NodeRef::findFreeOutput( 931 media_output* outOutput, 932 const media_format* format /*=0*/, 933 const char* name /*=0*/) const { 934 935 status_t err; 936 937 vector<media_output> outputs; 938 vector<media_output>::const_iterator it; 939 outputs.reserve(32); 940 941 err = getFreeOutputs(outputs); 942 if(err < B_OK) 943 return err; 944 945 it = find_if( 946 outputs.begin(), 947 outputs.end(), 948 match_endpoint_name_format<media_output>(name, format)); 949 if(it != outputs.end()) { 950 *outOutput = *it; 951 return B_OK; 952 } 953 return B_ERROR; 954 } 955 956 status_t NodeRef::findFreeOutput( 957 media_output* outOutput, 958 media_type type /*=B_MEDIA_UNKNOWN_TYPE*/, 959 const char* name /*=0*/) const { 960 961 status_t err; 962 963 vector<media_output> outputs; 964 vector<media_output>::const_iterator it; 965 outputs.reserve(32); 966 967 err = getFreeOutputs(outputs); 968 if(err < B_OK) 969 return err; 970 971 it = find_if( 972 outputs.begin(), 973 outputs.end(), 974 match_endpoint_name_type<media_output>(name, type)); 975 if(it != outputs.end()) { 976 *outOutput = *it; 977 return B_OK; 978 } 979 return B_ERROR; 980 } 981 982 983 // node endpoint access: vector versions (wrappers for BMediaRoster 984 // calls.) 985 986 status_t NodeRef::getFreeInputs( 987 vector<media_input>& ioInputs, 988 media_type filterType) const { 989 990 BMediaRoster* r = BMediaRoster::Roster(); 991 status_t err; 992 993 int32 count; 994 int32 bufferInc = 16; 995 int32 inputBufferSize = 16; 996 media_input* inputBuffer = new media_input[inputBufferSize]; 997 998 while(true) { 999 err = r->GetFreeInputsFor( 1000 m_info.node, inputBuffer, inputBufferSize, &count, filterType); 1001 if(err < B_OK) 1002 return err; 1003 1004 if(count == inputBufferSize) { 1005 // buffer too small; increase & try again 1006 inputBufferSize += bufferInc; 1007 delete [] inputBuffer; 1008 inputBuffer = new media_input[inputBufferSize]; 1009 continue; 1010 } 1011 1012 if(count) 1013 // copy found inputs into vector 1014 copy(inputBuffer, inputBuffer + count, 1015 back_inserter(ioInputs)); 1016 1017 break; 1018 } 1019 1020 // fix missing node info 1021 _fixInputs(ioInputs); 1022 1023 delete [] inputBuffer; 1024 return B_OK; 1025 } 1026 1027 // +++++ broken? 1028 status_t NodeRef::getConnectedInputs( 1029 vector<media_input>& ioInputs, 1030 media_type filterType) const { 1031 1032 BMediaRoster* r = BMediaRoster::Roster(); 1033 status_t err; 1034 1035 int32 count; 1036 int32 bufferInc = 16; 1037 int32 inputBufferSize = 16; 1038 media_input* inputBuffer = new media_input[inputBufferSize]; 1039 1040 while(true) { 1041 err = r->GetConnectedInputsFor( 1042 m_info.node, inputBuffer, inputBufferSize, &count); 1043 if(err < B_OK) 1044 return err; 1045 1046 if(count == inputBufferSize) { 1047 // buffer too small; increase & try again 1048 inputBufferSize += bufferInc; 1049 delete [] inputBuffer; 1050 inputBuffer = new media_input[inputBufferSize]; 1051 continue; 1052 } 1053 1054 if(count) 1055 // copy found inputs matching the given type into vector 1056 remove_copy_if(inputBuffer, inputBuffer + count, 1057 back_inserter(ioInputs), 1058 not1(match_endpoint_type<media_input>(filterType))); 1059 1060 break; 1061 } 1062 1063 // fix missing node info 1064 _fixInputs(ioInputs); 1065 1066 delete [] inputBuffer; 1067 return B_OK; 1068 } 1069 1070 status_t NodeRef::getFreeOutputs( 1071 vector<media_output>& ioOutputs, 1072 media_type filterType) const { 1073 1074 BMediaRoster* r = BMediaRoster::Roster(); 1075 status_t err; 1076 1077 int32 count; 1078 int32 bufferInc = 16; 1079 int32 outputBufferSize = 16; 1080 media_output* outputBuffer = new media_output[outputBufferSize]; 1081 1082 while(true) { 1083 err = r->GetFreeOutputsFor( 1084 m_info.node, outputBuffer, outputBufferSize, &count, filterType); 1085 if(err < B_OK) 1086 return err; 1087 1088 if(count == outputBufferSize) { 1089 // buffer too small; increase & try again 1090 outputBufferSize += bufferInc; 1091 delete [] outputBuffer; 1092 outputBuffer = new media_output[outputBufferSize]; 1093 continue; 1094 } 1095 1096 if(count) 1097 // copy found outputs into vector 1098 copy(outputBuffer, outputBuffer + count, 1099 back_inserter(ioOutputs)); 1100 1101 break; 1102 } 1103 1104 // fix missing node info 1105 _fixOutputs(ioOutputs); 1106 1107 delete [] outputBuffer; 1108 return B_OK; 1109 } 1110 1111 status_t NodeRef::getConnectedOutputs( 1112 vector<media_output>& ioOutputs, 1113 media_type filterType) const { 1114 1115 BMediaRoster* r = BMediaRoster::Roster(); 1116 status_t err; 1117 1118 int32 count; 1119 int32 bufferInc = 16; 1120 int32 outputBufferSize = 16; 1121 media_output* outputBuffer = new media_output[outputBufferSize]; 1122 1123 while(true) { 1124 err = r->GetConnectedOutputsFor( 1125 m_info.node, outputBuffer, outputBufferSize, &count); 1126 if(err < B_OK) 1127 return err; 1128 1129 if(count == outputBufferSize) { 1130 // buffer too small; increase & try again 1131 outputBufferSize += bufferInc; 1132 delete [] outputBuffer; 1133 outputBuffer = new media_output[outputBufferSize]; 1134 continue; 1135 } 1136 1137 if(count) 1138 // copy found outputs matching the given type into vector 1139 remove_copy_if(outputBuffer, outputBuffer + count, 1140 back_inserter(ioOutputs), 1141 not1(match_endpoint_type<media_output>(filterType))); 1142 1143 break; 1144 } 1145 1146 // fix missing node info 1147 _fixOutputs(ioOutputs); 1148 1149 delete [] outputBuffer; 1150 return B_OK; 1151 } 1152 1153 1154 // node endpoint access: array versions (wrappers for BMediaRoster 1155 // calls.) 1156 1157 status_t NodeRef::getFreeInputs( 1158 media_input* outInputs, 1159 int32 maxInputs, 1160 int32* outNumInputs, 1161 media_type filterType) const { 1162 1163 status_t err = BMediaRoster::Roster()->GetFreeInputsFor( 1164 m_info.node, outInputs, maxInputs, outNumInputs, filterType); 1165 1166 if(err < B_OK) 1167 return err; 1168 1169 // fix missing node info 1170 _fixInputs(outInputs, *outNumInputs); 1171 return err; 1172 } 1173 1174 1175 status_t NodeRef::getConnectedInputs( 1176 media_input* outInputs, 1177 int32 maxInputs, 1178 int32* outNumInputs) const { 1179 1180 status_t err = BMediaRoster::Roster()->GetConnectedInputsFor( 1181 m_info.node, outInputs, maxInputs, outNumInputs); 1182 1183 if(err < B_OK) 1184 return err; 1185 1186 // fix missing node info 1187 _fixInputs(outInputs, *outNumInputs); 1188 return err; 1189 } 1190 1191 status_t NodeRef::getFreeOutputs( 1192 media_output* outOutputs, 1193 int32 maxOutputs, 1194 int32* outNumOutputs, 1195 media_type filterType) const { 1196 1197 status_t err = BMediaRoster::Roster()->GetFreeOutputsFor( 1198 m_info.node, outOutputs, maxOutputs, outNumOutputs, filterType); 1199 1200 if(err < B_OK) 1201 return err; 1202 1203 // fix missing node info 1204 _fixOutputs(outOutputs, *outNumOutputs); 1205 return err; 1206 } 1207 1208 status_t NodeRef::getConnectedOutputs( 1209 media_output* outOutputs, 1210 int32 maxOutputs, 1211 int32* outNumOutputs) const { 1212 1213 status_t err = BMediaRoster::Roster()->GetConnectedOutputsFor( 1214 m_info.node, outOutputs, maxOutputs, outNumOutputs); 1215 1216 if(err < B_OK) 1217 return err; 1218 1219 // fix missing node info 1220 _fixOutputs(outOutputs, *outNumOutputs); 1221 return err; 1222 } 1223 1224 1225 // -------------------------------------------------------- // 1226 // *** IPersistent 1227 // -------------------------------------------------------- // 1228 1229 // ! 1230 #if CORTEX_XML 1231 // ! 1232 1233 // +++++ 1234 1235 // ! 1236 #endif /*CORTEX_XML*/ 1237 // ! 1238 1239 // -------------------------------------------------------- // 1240 // *** BHandler: 1241 // -------------------------------------------------------- // 1242 1243 void NodeRef::MessageReceived( 1244 BMessage* message) { 1245 1246 D_MESSAGE(( 1247 "NodeRef['%s']::MessageReceived(): %c%c%c%c\n", 1248 name(), 1249 message->what >> 24, 1250 (message->what >> 16) & 0xff, 1251 (message->what >> 8) & 0xff, 1252 (message->what) & 0xff)); 1253 status_t err; 1254 1255 switch(message->what) { 1256 case M_SET_RUN_MODE: 1257 { 1258 // set run mode & delay (if given) 1259 int32 runMode; 1260 bigtime_t delay = 0LL; 1261 err = message->FindInt32("runMode", &runMode); 1262 if(err < B_OK) { 1263 PRINT(( 1264 "! NodeRef::MessageReceived(M_SET_RUN_MODE): no value found.\n")); 1265 break; 1266 } 1267 if(runMode == BMediaNode::B_RECORDING) 1268 message->FindInt64("delay", &delay); // optional 1269 1270 setRunMode(runMode, delay); 1271 } 1272 break; 1273 1274 1275 case M_PREROLL: 1276 // +++++ 1277 break; 1278 1279 case M_SET_CYCLING: 1280 { 1281 bool cycling; 1282 err = message->FindBool("cycling", &cycling); 1283 if(err < B_OK) { 1284 int32 val; 1285 err = message->FindInt32("be:value", &val); 1286 if(err < B_OK) { 1287 PRINT(( 1288 "! NodeRef::MessageReceived(M_SET_CYCLING): no value found.\n")); 1289 break; 1290 } 1291 cycling = val; 1292 } 1293 1294 setCycling(cycling); 1295 } 1296 break; 1297 1298 case B_MEDIA_NODE_STOPPED: 1299 // PRINT(("### B_MEDIA_NODE_STOPPED\n")); 1300 // 1301 // if still marked running, let the group know [e.moon 11oct99] 1302 if(m_running) { 1303 m_running = false; 1304 m_stopQueued = false; 1305 1306 if(m_group) { 1307 Autolock _l(m_group); 1308 m_group->_refStopped(this); 1309 } 1310 } 1311 1312 break; 1313 1314 case NodeSyncThread::M_SYNC_COMPLETE: { 1315 // [e.moon 14oct99] position-report messages are now sent 1316 // by the NodeSyncThread. 1317 1318 Autolock _l(this); 1319 1320 // unpack message 1321 bigtime_t when, position; 1322 err = message->FindInt64("perfTime", &when); 1323 ASSERT(err == B_OK); 1324 err = message->FindInt64("position", &position); 1325 ASSERT(err == B_OK); 1326 1327 _handlePositionUpdate(when, position); 1328 break; 1329 } 1330 1331 default: 1332 _inherited::MessageReceived(message); 1333 } 1334 } 1335 1336 // -------------------------------------------------------- // 1337 // *** IObservable: [20aug99] 1338 // -------------------------------------------------------- // 1339 1340 void NodeRef::observerAdded( 1341 const BMessenger& observer) { 1342 1343 BMessage m(M_OBSERVER_ADDED); 1344 m.AddInt32("nodeID", id()); 1345 m.AddMessenger("target", BMessenger(this)); 1346 observer.SendMessage(&m); 1347 } 1348 1349 void NodeRef::observerRemoved( 1350 const BMessenger& observer) { 1351 1352 BMessage m(M_OBSERVER_REMOVED); 1353 m.AddInt32("nodeID", id()); 1354 m.AddMessenger("target", BMessenger(this)); 1355 observer.SendMessage(&m); 1356 } 1357 1358 void NodeRef::notifyRelease() { 1359 1360 BMessage m(M_RELEASED); 1361 m.AddInt32("nodeID", id()); 1362 m.AddMessenger("target", BMessenger(this)); 1363 notify(&m); 1364 } 1365 1366 void NodeRef::releaseComplete() { 1367 // +++++ 1368 } 1369 1370 // -------------------------------------------------------- // 1371 // *** ILockable: pass lock requests to parent group, 1372 // or manager if no group found 1373 // -------------------------------------------------------- // 1374 1375 // this is hideous. [24aug99] 1376 // it must die soon. 1377 1378 // The two-stage lock appears safe UNLESS it's multiply acquired 1379 // (and the NodeManager is locked somewhere in between.) Then 1380 // it's deadlocks all around... 1381 1382 // safe two-stage lock (only WRITE locking is supported) 1383 // Notes: 1384 // a) a NodeRef either belongs to a group (m_group != 0) or 1385 // is free. If the ref is free, the NodeManager is the 1386 // target for locking; otherwise the group is the 'lockee'. 1387 // b) operations which affect a NodeRef's group affiliation 1388 // (ie. adding or removing a node to/from a group) must 1389 // lock first the NodeManager, then the NodeGroup. The 1390 // locks should be released in the opposite order. 1391 1392 bool NodeRef::lock( 1393 lock_t type, 1394 bigtime_t timeout) { 1395 1396 D_LOCK(("*** NodeRef::lock(): %ld\n", find_thread(0))); 1397 1398 ASSERT(type == WRITE); 1399 ASSERT(m_manager); 1400 1401 // lock manager 1402 if(!m_manager->lock(type, timeout)) 1403 return false; 1404 1405 // transfer lock to group, if any 1406 NodeGroup* group = m_group; 1407 if(!group) 1408 return true; 1409 1410 bool ret = m_group->lock(type, timeout); 1411 1412 m_manager->unlock(); 1413 1414 D_LOCK(("*** NodeRef::lock() ACQUIRED: %ld\n", find_thread(0))); 1415 1416 return ret; 1417 } 1418 1419 bool NodeRef::unlock( 1420 lock_t type) { 1421 1422 D_LOCK(("*** NodeRef::unlock(): %ld\n", find_thread(0))); 1423 1424 ASSERT(type == WRITE); 1425 ASSERT(m_manager); 1426 1427 NodeGroup* group = m_group; 1428 if(group) { 1429 bool ret = m_group->unlock(type); 1430 D_LOCK(("*** NodeRef::unlock() RELEASED: %ld\n", find_thread(0))); 1431 return ret; 1432 } 1433 1434 bool ret = m_manager->unlock(type); 1435 1436 D_LOCK(("*** NodeRef::unlock() RELEASED: %ld\n", find_thread(0))); 1437 return ret; 1438 } 1439 1440 bool NodeRef::isLocked( 1441 lock_t type) const { 1442 1443 ASSERT(type == WRITE); 1444 ASSERT(m_manager); 1445 1446 NodeGroup* group = m_group; 1447 if(group) 1448 return m_group->isLocked(type); 1449 1450 return m_manager->isLocked(type); 1451 } 1452 1453 // -------------------------------------------------------- // 1454 // *** ctor 1455 // -------------------------------------------------------- // 1456 1457 NodeRef::NodeRef( 1458 const media_node& node, 1459 NodeManager* manager, 1460 uint32 userFlags, 1461 uint32 implFlags) : 1462 1463 m_manager(manager), 1464 m_group(0), 1465 m_flags(userFlags), 1466 m_implFlags(implFlags), 1467 m_runMode(0), 1468 m_recordingDelay(0LL), 1469 m_watching(false), 1470 m_addonHint(0), 1471 m_positionReportsEnabled(false), 1472 m_positionReportsStarted(false), 1473 m_positionUpdatePeriod(s_defaultPositionUpdatePeriod), 1474 m_tpLastPositionUpdate(0LL), 1475 m_lastPosition(0LL), 1476 m_positionThread(0), 1477 m_running(false), 1478 m_nodeReleased(false), 1479 m_cycle(false), 1480 m_prerolled(false), 1481 // m_cycleSyncThread(0), 1482 m_stopQueued(false), 1483 m_latency(0LL) { 1484 1485 ASSERT(manager); 1486 1487 if(!m_manager->Lock()) { 1488 ASSERT(!"m_manager->Lock() failed"); 1489 } 1490 m_manager->AddHandler(this); 1491 m_manager->Unlock(); 1492 1493 // fetch node details 1494 BMediaRoster* r = BMediaRoster::Roster(); 1495 status_t err = r->GetLiveNodeInfo( 1496 node, 1497 &m_info); 1498 1499 if(err < B_OK) { 1500 PRINT(( 1501 "!!! NodeRef(): BMediaRoster::GetLiveNodeInfo(%ld) failed:\n" 1502 " %s\n", 1503 node.node, 1504 strerror(err))); 1505 // at least store node info 1506 m_info.node = node; 1507 } 1508 1509 // name self after node 1510 SetName(m_info.name); 1511 1512 // init Media Roster connection [e.moon 11oct99] 1513 if(!(m_flags & NO_ROSTER_WATCH)) { 1514 r->StartWatching( 1515 BMessenger(this), 1516 m_info.node, 1517 B_MEDIA_NODE_STOPPED); 1518 m_watching = true; 1519 } 1520 } 1521 // -------------------------------------------------------- // 1522 // *** endpoint-fixing operations (no lock required) 1523 // -------------------------------------------------------- // 1524 1525 template <class T> 1526 class fixEndpointFn : public unary_function<T&, void> { 1527 const media_node& node; 1528 public: 1529 fixEndpointFn(const media_node& _n) : node(_n) {} 1530 void operator()(T& endpoint) { 1531 // PRINT(( 1532 // "fixEndpointFn(): endpoint '%s', node ID %ld\n", 1533 // endpoint.name, endpoint.node.node)); 1534 if(endpoint.node != node) { 1535 PRINT(( 1536 " fixing '%s'\n", endpoint.name)); 1537 endpoint.node = node; 1538 } 1539 } 1540 }; 1541 1542 // 'fix' (fill in node if needed) sets of inputs/outputs 1543 void NodeRef::_fixInputs( 1544 media_input* inputs, 1545 int32 count) const { 1546 1547 D_METHOD(( 1548 "NodeRef[%s]::fixInputs()\n", m_info.name)); 1549 1550 for_each( 1551 inputs, 1552 inputs+count, 1553 fixEndpointFn<media_input>(node())); 1554 } 1555 1556 void NodeRef::_fixInputs( 1557 vector<media_input>& inputs) const { 1558 1559 D_METHOD(( 1560 "NodeRef[%s]::fixInputs()\n", m_info.name)); 1561 1562 for_each( 1563 inputs.begin(), 1564 inputs.end(), 1565 fixEndpointFn<media_input>(node())); 1566 } 1567 1568 void NodeRef::_fixOutputs( 1569 media_output* outputs, 1570 int32 count) const { 1571 1572 D_METHOD(( 1573 "NodeRef[%s]::fixOutputs()\n", m_info.name)); 1574 1575 for_each( 1576 outputs, 1577 outputs+count, 1578 fixEndpointFn<media_output>(node())); 1579 } 1580 1581 void NodeRef::_fixOutputs( 1582 vector<media_output>& outputs) const { 1583 1584 D_METHOD(( 1585 "NodeRef[%s]::fixOutputs()\n", m_info.name)); 1586 1587 for_each( 1588 outputs.begin(), 1589 outputs.end(), 1590 fixEndpointFn<media_output>(node())); 1591 } 1592 1593 // -------------------------------------------------------- // 1594 // *** internal/NodeManager operations (LOCK REQUIRED) 1595 // -------------------------------------------------------- // 1596 1597 // call after instantiation to register the dormant_node_info 1598 // used to select this add-on node 1599 1600 void NodeRef::_setAddonHint( 1601 const dormant_node_info* info, 1602 const entry_ref* file) { 1603 1604 assert_locked(this); 1605 1606 if(m_addonHint) 1607 delete m_addonHint; 1608 1609 m_addonHint = new addon_hint(info, file); 1610 } 1611 1612 // call to set a new group; if 0, the node must have no 1613 // connections 1614 void NodeRef::_setGroup( 1615 NodeGroup* group) { 1616 assert_locked(this); 1617 1618 m_group = group; 1619 1620 if(!LockLooper()) { 1621 ASSERT(!"LockLooper() failed."); 1622 } 1623 BMessage m(M_GROUP_CHANGED); 1624 m.AddInt32("nodeID", (int32)m_info.node.node); 1625 m.AddInt32("groupID", m_group ? (int32)m_group->id() : 0); 1626 notify(&m); 1627 UnlockLooper(); 1628 } 1629 1630 // *** NodeGroup API *** 1631 // 9aug99: moved from NodeGroup 1632 1633 // initialize the given node's transport-state members 1634 // (this may be called from the transport thread or from 1635 // an API-implementation method.) 1636 1637 status_t NodeRef::_initTransportState() { 1638 assert_locked(this); 1639 1640 D_METHOD(( 1641 "NodeRef('%s')::_initTransportState()\n", 1642 name())); 1643 1644 // init transport state for this node 1645 m_prerolled = false; 1646 m_tpStart = 0LL; 1647 m_tpLastSeek = 0LL; 1648 m_lastSeekPos = 0LL; 1649 1650 // +++++ init position reporting stuff here? 1651 1652 return B_OK; 1653 } 1654 1655 status_t NodeRef::_setTimeSource( 1656 media_node_id timeSourceID) { 1657 assert_locked(this); 1658 1659 D_METHOD(( 1660 "NodeRef('%s')::_setTimeSource(%ld)\n", 1661 name(), timeSourceID)); 1662 status_t err; 1663 1664 // set time source 1665 ASSERT(timeSourceID != media_node::null.node); 1666 D_ROSTER(("# roster->SetTimeSourceFor()\n")); 1667 err = m_manager->roster->SetTimeSourceFor( 1668 id(), timeSourceID); 1669 1670 if(err < B_OK) { 1671 PRINT(( 1672 "* NodeRef('%s')::_setTimeSource(%ld):\n" 1673 " SetTimeSourceFor() failed: %s\n", 1674 name(), timeSourceID, strerror(err))); 1675 } 1676 1677 return err; 1678 } 1679 1680 status_t NodeRef::_setRunMode( 1681 const uint32 runMode, 1682 bigtime_t delay) { 1683 assert_locked(this); 1684 1685 D_METHOD(( 1686 "NodeRef('%s')::_setRunMode(%ld : %Ld)\n", 1687 name(), runMode, delay)); 1688 status_t err; 1689 1690 1691 BMediaNode::run_mode m = 1692 // if group is in offline mode, so are all its nodes 1693 (runMode == BMediaNode::B_OFFLINE) ? 1694 (BMediaNode::run_mode)runMode : 1695 // if non-0, the node's setting is used 1696 (m_runMode > 0) ? 1697 (BMediaNode::run_mode)m_runMode : 1698 (BMediaNode::run_mode)runMode; 1699 ASSERT(m > 0); 1700 1701 // +++++ additional producer run-mode delay support here? 1702 1703 if( 1704 kind() & B_BUFFER_PRODUCER && 1705 runMode == BMediaNode::B_RECORDING) { 1706 1707 D_ROSTER(("# roster->SetProducerRunModeDelay()\n")); 1708 err = m_manager->roster->SetProducerRunModeDelay( 1709 node(), delay, m); 1710 if(err < B_OK) { 1711 PRINT(( 1712 "NodeRef('%s')::_setRunMode(): SetProducerRunModeDelay(%Ld) failed: %s\n", 1713 name(), delay, strerror(err))); 1714 } 1715 } else { 1716 1717 D_ROSTER(("# roster->SetRunModeNode()\n")); 1718 err = m_manager->roster->SetRunModeNode( 1719 node(), m); 1720 if(err < B_OK) { 1721 PRINT(( 1722 "NodeRef('%s')::_setRunMode(): SetRunModeNode(%d) failed: %s\n", 1723 name(), m, strerror(err))); 1724 } 1725 } 1726 1727 return err; 1728 } 1729 1730 status_t NodeRef::_setRunModeAuto( 1731 const uint32 runMode) { 1732 1733 if( 1734 kind() && B_BUFFER_PRODUCER && 1735 runMode == BMediaNode::B_RECORDING) { 1736 1737 return _setRunMode( 1738 runMode, 1739 calculateRecordingModeDelay()); 1740 1741 } else 1742 return _setRunMode(runMode); 1743 } 1744 1745 // seek and preroll the given node. 1746 // *** this method should not be called from the transport thread 1747 // (since preroll operations can block for a relatively long time.) 1748 // 1749 // returns B_NOT_ALLOWED if the node is running, or if its NO_PREROLL 1750 // flag is set; otherwise, returns B_OK on success or a Media Roster 1751 // error. 1752 1753 status_t NodeRef::_preroll( 1754 bigtime_t position) { 1755 assert_locked(this); 1756 1757 D_METHOD(( 1758 "NodeRef('%s')::_preroll(%Ld)\n", 1759 name(), position)); 1760 status_t err; 1761 1762 // make sure the node can be and wants to be prerolled 1763 if(m_running || 1764 m_flags & NO_PREROLL) 1765 return B_NOT_ALLOWED; 1766 1767 if(!(m_flags & NO_SEEK)) { 1768 // seek the node first 1769 err = BMediaRoster::Roster()->SeekNode( 1770 node(), 1771 position, 1772 0LL); 1773 1774 if(err < B_OK) { 1775 PRINT(( 1776 "*** NodeRef('%s')::_preroll(%Ld): BMediaRoster::SeekNode():\n" 1777 " %s\n", 1778 name(), position, strerror(err))); 1779 return err; 1780 } 1781 } 1782 1783 // preroll the node (*** this blocks until the node's Preroll() 1784 // implementation returns ***) 1785 1786 err = BMediaRoster::Roster()->PrerollNode( 1787 node()); 1788 1789 if(err < B_OK) { 1790 PRINT(( 1791 "*** NodeRef('%s')::_preroll(%Ld): BMediaRoster::PrerollNode():\n" 1792 " %s\n", 1793 name(), position, strerror(err))); 1794 return err; 1795 } 1796 1797 m_prerolled = true; 1798 m_tpLastSeek = 0LL; 1799 m_lastSeekPos = position; 1800 1801 return B_OK; 1802 } 1803 1804 // seek the given node if possible 1805 // (this may be called from the transport thread or from 1806 // an API-implementation method.) 1807 1808 status_t NodeRef::_seek( 1809 bigtime_t position, 1810 bigtime_t when) { 1811 assert_locked(this); 1812 1813 D_METHOD(( 1814 "NodeRef('%s')::_seek(to %Ld, at %Ld)\n", 1815 name(), position, when)); 1816 1817 if(m_flags & NO_SEEK) 1818 // the node should not be seek'd 1819 return B_OK; 1820 1821 if(m_prerolled && m_lastSeekPos == position) 1822 // the node has already been advanced to the proper position 1823 return B_OK; 1824 1825 // do it 1826 status_t err = BMediaRoster::Roster()->SeekNode( 1827 node(), position, when); 1828 1829 if(err < B_OK) { 1830 PRINT(( 1831 "*** NodeRef('%s')::_seek(to %Ld, at %Ld): BMediaRoster::SeekNode():\n" 1832 " %s\n", 1833 name(), position, when, strerror(err))); 1834 return err; 1835 } 1836 1837 // update node state 1838 m_tpLastSeek = when; 1839 m_lastSeekPos = position; 1840 1841 // node can't be considered prerolled after a seek 1842 m_prerolled = false; 1843 1844 return B_OK; 1845 } 1846 1847 // seek the given (stopped) node 1848 // (this may be called from the transport thread or from 1849 // an API-implementation method.) 1850 1851 status_t NodeRef::_seekStopped( 1852 bigtime_t position) { 1853 assert_locked(this); 1854 1855 D_METHOD(( 1856 "NodeRef('%s')::_seekStopped(to %Ld)\n", 1857 name(), position)); 1858 1859 if(m_running) 1860 return B_NOT_ALLOWED; 1861 1862 return _seek(position, 0LL); 1863 } 1864 1865 1866 // start the given node, if possible & necessary, at 1867 // the given time 1868 // (this may be called from the transport thread or from 1869 // an API-implementation method.) 1870 1871 status_t NodeRef::_start( 1872 bigtime_t when) { 1873 assert_locked(this); 1874 1875 D_METHOD(( 1876 "NodeRef('%s')::_start(at %Ld)\n", 1877 name(), when)); 1878 1879 if(isRunning()) { 1880 D_METHOD(( 1881 " * node already running; aborting\n")); 1882 return B_OK; // +++++ is this technically an error? 1883 } 1884 1885 // +++++ is this proper? 1886 ASSERT(m_group); 1887 ASSERT( 1888 m_group->m_transportState == NodeGroup::TRANSPORT_RUNNING || 1889 m_group->m_transportState == NodeGroup::TRANSPORT_STARTING); 1890 1891 if(m_flags & NO_START_STOP) { 1892 D_METHOD(( 1893 " * NO_START_STOP; aborting\n")); 1894 return B_OK; 1895 } 1896 1897 D_ROSTER(("# roster->StartNode(%ld)\n", id())); 1898 status_t err = BMediaRoster::Roster()->StartNode( 1899 node(), when); 1900 1901 if(err < B_OK) { 1902 PRINT(( 1903 " * StartNode(%ld) failed: '%s'\n", 1904 id(), strerror(err))); 1905 return err; 1906 } 1907 1908 // update state 1909 m_running = true; 1910 m_tpStart = when; 1911 1912 // fetch new node latency 1913 _updateLatency(); 1914 1915 // start position tracking thread if needed 1916 m_positionReportsStarted = false; 1917 if(m_positionReportsEnabled) 1918 _startPositionThread(); 1919 1920 return B_OK; 1921 } 1922 1923 // stop the given node (which may or may not still be 1924 // a member of this group.) 1925 // (this may be called from the transport thread or from 1926 // an API-implementation method.) 1927 1928 status_t NodeRef::_stop() { 1929 assert_locked(this); 1930 1931 D_METHOD(( 1932 "NodeRef('%s')::_stop()\n", 1933 name())); 1934 1935 if(!isRunning()) 1936 return B_OK; // +++++ error? 1937 1938 if(m_flags & NO_START_STOP || m_flags & NO_STOP) 1939 return B_OK; 1940 1941 D_ROSTER(("# roster->StopNode(%ld)\n", id())); 1942 status_t err = BMediaRoster::Roster()->StopNode( 1943 node(), 0, true); 1944 1945 if(err < B_OK) 1946 return err; 1947 1948 // 9aug99: refuse further position notification 1949 _stopPositionThread(); 1950 1951 // clear node's state 1952 m_running = false; 1953 m_stopQueued = false; // asked for immediate stop [e.moon 11oct99] 1954 return _initTransportState(); 1955 } 1956 1957 // roll the given node, if possible 1958 // (this may be called from the transport thread or from 1959 // an API-implementation method.) 1960 status_t NodeRef::_roll( 1961 bigtime_t start, 1962 bigtime_t stop, 1963 bigtime_t position) { 1964 assert_locked(this); 1965 1966 D_METHOD(( 1967 "NodeRef('%s')::_roll(%Ld to %Ld, from %Ld)\n", 1968 name(), start, stop, position)); 1969 status_t err; 1970 1971 // roll only if the node can be started & stopped, 1972 // AND if this NodeRef is watching the Media Roster. 1973 if( 1974 m_flags & NO_START_STOP || 1975 m_flags & NO_STOP || 1976 m_flags & NO_ROSTER_WATCH) 1977 return B_NOT_ALLOWED; 1978 1979 if(isRunning()) 1980 return B_NOT_ALLOWED; 1981 1982 ASSERT(m_group); 1983 ASSERT( 1984 m_group->m_transportState == NodeGroup::TRANSPORT_RUNNING || 1985 m_group->m_transportState == NodeGroup::TRANSPORT_STARTING); 1986 1987 D_ROSTER(("# roster->RollNode(%ld)\n", id())); 1988 if(m_flags & NO_SEEK) 1989 err = BMediaRoster::Roster()->RollNode( 1990 node(), start, stop); 1991 else 1992 err = BMediaRoster::Roster()->RollNode( 1993 node(), start, stop, position); 1994 1995 if(err < B_OK) { 1996 PRINT(( 1997 "NodeRef('%s')::_roll(%Ld to %Ld, from %Ld)\n" 1998 "!!! BMediaRoster::RollNode(%ld) failed: '%s'\n", 1999 name(), start, stop, position, id(), strerror(err))); 2000 return err; 2001 } 2002 2003 // update state 2004 m_running = true; 2005 m_stopQueued = true; // remember that node will stop on its own [e.moon 11oct99] 2006 m_tpStart = start; 2007 2008 // fetch new node latency 2009 _updateLatency(); 2010 2011 // start position tracking thread if needed 2012 m_positionReportsStarted = false; 2013 if(m_positionReportsEnabled) 2014 _startPositionThread(); 2015 2016 return B_OK; 2017 } 2018 2019 // [28sep99 e.moon] 2020 // refresh the node's current latency; if I reference 2021 // a B_RECORDING node, update its 'producer delay'. 2022 2023 status_t NodeRef::_updateLatency() { 2024 assert_locked(this); 2025 2026 // [11nov99 e.moon] don't bother if it's not a producer: 2027 if(!(kind() & B_BUFFER_PRODUCER)) { 2028 m_latency = 0LL; 2029 return B_OK; 2030 } 2031 2032 bigtime_t latency; 2033 status_t err = BMediaRoster::Roster()->GetLatencyFor( 2034 node(), 2035 &latency); 2036 if(err < B_OK) { 2037 PRINT(( 2038 "* NodeRef('%s')::_updateLatency(): GetLatencyFor() failed:\n" 2039 " %s\n", 2040 name(), strerror(err))); 2041 2042 return err; 2043 } 2044 2045 // success 2046 m_latency = latency; 2047 2048 // update run-mode & delay if necessary 2049 if( 2050 m_runMode == BMediaNode::B_RECORDING || 2051 (m_runMode == 0 && m_group && m_group->runMode() == BMediaNode::B_RECORDING)) 2052 _setRunModeAuto(BMediaNode::B_RECORDING); 2053 2054 return B_OK; 2055 } 2056 2057 // Figure the earliest time at which the given node can be started. 2058 // Also calculates the position at which it should start from to 2059 // play in sync with other nodes in the group, if the transport is 2060 // running; if stopped, *outPosition will be set to the current 2061 // start position. 2062 // Pass the estimated amount of time needed to prepare the 2063 // node for playback (ie. preroll & a little fudge factor) in 2064 // startDelay. 2065 // 2066 // (this may be called from the transport thread or from 2067 // an API-implementation method.) 2068 2069 status_t NodeRef::_calcStartTime( 2070 bigtime_t startDelay, 2071 bigtime_t* outTime, 2072 bigtime_t* outPosition) { 2073 assert_locked(this); 2074 2075 // +++++ 2076 2077 return B_ERROR; 2078 } 2079 2080 2081 // -------------------------------------------------------- // 2082 // *** Position and cycle thread management *** (LOCK REQUIRED) 2083 // -------------------------------------------------------- // 2084 2085 status_t NodeRef::_startPositionThread() { 2086 assert_locked(this); 2087 ASSERT(m_group); 2088 status_t err; 2089 2090 if(!m_positionReportsEnabled) 2091 return B_NOT_ALLOWED; 2092 2093 if(m_positionThread) 2094 _stopPositionThread(); 2095 2096 m_positionThread = new NodeSyncThread( 2097 m_info.node, 2098 new BMessenger(this)); 2099 2100 // send an initial position report if necessary 2101 if(!m_positionReportsStarted) { 2102 m_positionReportsStarted = true; 2103 2104 err = _handlePositionUpdate( 2105 m_tpStart, 2106 m_lastSeekPos); 2107 2108 if(err < B_OK) { 2109 PRINT(( 2110 "* NodeRef::_startPositionThread(): _handlePositionUpdate() failed:\n" 2111 " %s\\n", 2112 strerror(err))); 2113 return err; 2114 } 2115 } 2116 else { 2117 2118 // figure when the last jump in position occurred 2119 bigtime_t tpFrom = (m_tpLastSeek > m_tpStart) ? m_tpLastSeek : m_tpStart; 2120 2121 // figure the corresponding position 2122 bigtime_t lastPosition = m_lastSeekPos; 2123 2124 // figure the next time for a position report 2125 BTimeSource* ts = m_group->m_timeSourceObj; 2126 2127 bigtime_t tpTarget = ts->Now() + m_positionUpdatePeriod; 2128 bigtime_t targetPosition = lastPosition + (tpTarget-tpFrom); 2129 2130 err = _schedulePositionUpdate( 2131 tpTarget, 2132 targetPosition); 2133 2134 if(err < B_OK) { 2135 PRINT(( 2136 "* NodeRef::_createPositionThread(): _schedulePositionUpdate() failed:\n" 2137 " %s\\n", 2138 strerror(err))); 2139 return err; 2140 } 2141 } 2142 2143 return B_OK; 2144 } 2145 2146 status_t NodeRef::_handlePositionUpdate( 2147 bigtime_t perfTime, 2148 bigtime_t position) { 2149 assert_locked(this); 2150 status_t err; 2151 2152 if(!m_running) { 2153 PRINT(( 2154 "* NodeRef::_handlePositionUpdate(): not running.\n")); 2155 return B_NOT_ALLOWED; 2156 } 2157 2158 if(!m_positionReportsEnabled) { 2159 PRINT(( 2160 "* NodeRef::_handlePositionUpdate(): position reports disabled.\n")); 2161 return B_NOT_ALLOWED; 2162 } 2163 2164 // store info 2165 m_tpLastPositionUpdate = perfTime; 2166 m_lastPosition = position; 2167 2168 // relay notification to all 'position listeners' 2169 _notifyPosition(perfTime, position); 2170 2171 // schedule next update 2172 err = _schedulePositionUpdate( 2173 perfTime + m_positionUpdatePeriod, 2174 position + m_positionUpdatePeriod); 2175 2176 if(err < B_OK) { 2177 PRINT(( 2178 "* NodeRef::_handlePositionUpdate(): _schedulePositionUpdate() failed:\n" 2179 " %s\n", 2180 strerror(err))); 2181 } 2182 return err; 2183 } 2184 2185 status_t NodeRef::_schedulePositionUpdate( 2186 bigtime_t when, 2187 bigtime_t position) { 2188 assert_locked(this); 2189 status_t err; 2190 2191 if(!m_positionReportsEnabled) 2192 return B_NOT_ALLOWED; 2193 ASSERT(m_positionThread); 2194 2195 if(m_cycle && m_group->_cycleValid()) { 2196 if(position >= m_group->endPosition()) { 2197 // snap to start of next cycle 2198 when = m_group->_cycleBoundary(); 2199 position = m_group->startPosition(); 2200 } 2201 } 2202 2203 //// position_sync_msg m = { 2204 //// id(), 2205 //// m_group->id(), 2206 //// when, 2207 //// position 2208 //// }; 2209 // 2210 //// PRINT(( 2211 //// "NodeRef::_schedulePositionUpdate():\n" 2212 //// " when = %Ld\n" 2213 //// " position = %Ld\n", 2214 //// when, position)); 2215 // 2216 // m_positionSyncThread->setPosition(position); 2217 // 2218 // if(first) 2219 // err = m_positionSyncThread->go(when); 2220 // else 2221 // err = m_positionSyncThread->reschedule(when); 2222 2223 err = m_positionThread->sync(when, position, B_INFINITE_TIMEOUT); 2224 2225 if(err < B_OK) { 2226 PRINT(( 2227 "! NodeRef::_schedulePositionUpdate(): m_positionThread->sync() failed:\n" 2228 " %s\n", strerror(err))); 2229 } 2230 return err; 2231 } 2232 2233 status_t NodeRef::_stopPositionThread() { 2234 assert_locked(this); 2235 2236 if(!m_positionThread) 2237 return B_NOT_ALLOWED; 2238 2239 delete m_positionThread; 2240 m_positionThread = 0; 2241 2242 return B_OK; 2243 } 2244 2245 2246 // Send a message to all position listeners 2247 status_t NodeRef::_notifyPosition( 2248 bigtime_t when, 2249 bigtime_t position) { 2250 assert_locked(this); 2251 status_t err = B_OK; 2252 2253 if(!m_positionReportsEnabled) 2254 return B_NOT_ALLOWED; 2255 2256 BMessage message(M_POSITION); 2257 message.AddInt32("nodeID", id()); 2258 message.AddInt64("when", when); 2259 message.AddInt64("position", position); 2260 2261 m_positionInvoker.Invoke(&message); 2262 2263 return err; 2264 } 2265 2266 // END -- NodeRef.cpp -- 2267