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