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