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