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.h (Cortex/NodeManager) 33 // 34 // * PURPOSE 35 // Represents a NodeManager reference to a live Media Kit Node. 36 // 37 // * FEATURES UNDER CONSIDERATION +++++ 38 // - lazy referencing: m_released becomes m_referenced; only reference 39 // externally created nodes once they've been grouped or connected. 40 // +++++ or disconnected? keep a'thinkin... 41 // - expose dormant_node_info 42 // 43 // * HISTORY 44 // e.moon 11aug99 Added kind(). 45 // e.moon 9aug99 Moved position & cycle threads into NodeRef; 46 // no more 'group transport thread'. 47 // e.moon 25jun99 Begun 48 49 #ifndef __NodeRef_H__ 50 #define __NodeRef_H__ 51 52 #include <MediaAddOn.h> 53 #include <MediaNode.h> 54 #include <String.h> 55 56 #include <vector> 57 58 #include "ILockable.h" 59 #include "MultiInvoker.h" 60 #include "ObservableHandler.h" 61 #include "observe.h" 62 63 #include "cortex_defs.h" 64 65 __BEGIN_CORTEX_NAMESPACE 66 67 class Connection; 68 class NodeManager; 69 class NodeGroup; 70 class NodeSyncThread; 71 72 class NodeRef : 73 public ObservableHandler, 74 protected ILockable { 75 76 typedef ObservableHandler _inherited; 77 78 friend class NodeManager; 79 friend class NodeGroup; 80 81 public: // *** messages 82 enum message_t { 83 // OUTBOUND 84 // nodeID: int32 85 // target: BMessenger 86 M_OBSERVER_ADDED =NodeRef_message_base, 87 M_OBSERVER_REMOVED, 88 M_RELEASED, 89 90 // OUTBOUND 91 // nodeID: int32 92 // groupID: int32 93 M_GROUP_CHANGED, 94 95 // nodeID: int32 96 // runMode: int32 97 M_RUN_MODE_CHANGED, 98 99 // +++++ 100 M_INPUTS_CHANGED, //nyi 101 M_OUTPUTS_CHANGED, //nyi 102 103 // OUTBOUND 104 // * only sent to position listeners 105 // nodeID: int32 106 // when: int64 107 // position: int64 108 M_POSITION, 109 110 // INBOUND 111 // runMode: int32 112 // delay: int64 (bigtime_t; applies only to B_RECORDING mode) 113 M_SET_RUN_MODE, 114 115 // INBOUND 116 M_PREROLL, 117 118 // INBOUND 119 // "cycling"; bool (OR "be:value"; int32) 120 M_SET_CYCLING, 121 122 // OUTBOUND 123 // "cycling"; bool 124 M_CYCLING_CHANGED 125 }; 126 127 public: // *** flags 128 enum flag_t { 129 // node-level transport restrictions 130 NO_START_STOP = 1<<1, 131 NO_SEEK = 1<<2, 132 NO_PREROLL = 1<<3, 133 134 // [e.moon 28sep99] useful for misbehaved nodes 135 NO_STOP = 1<<4, 136 137 // [e.moon 11oct99] 138 // Disables media-roster connection (which currently 139 // only makes use of B_MEDIA_NODE_STOPPED.) 140 // This flag may become deprecated as the Media Kit 141 // evolves (ie. more node-level notifications come 142 // along.) 143 NO_ROSTER_WATCH = 1<<5, 144 145 // [e.moon 14oct99] 146 // Disables position reporting (via BMediaRoster::SyncToNode().) 147 // Some system-provided nodes tend to explode when SyncToNode() is 148 // called on them (like the video-file player in BeOS R4.5.2). 149 NO_POSITION_REPORTING = 1<<6 150 }; 151 152 public: // *** dtor 153 154 // free the node (this call will result in the eventual 155 // deletion of the object.) 156 // returns B_OK on success; B_NOT_ALLOWED if release() has 157 // already been called; other error codes if the Media Roster 158 // call fails. 159 160 status_t release(); 161 162 // call release() rather than deleting NodeRef objects 163 virtual ~NodeRef(); 164 165 public: // *** const accessors 166 // [e.moon 13oct99] moved method definitions here to keep inline 167 // in the face of a balky PPC compiler node()168 inline const media_node& node() const { return m_info.node; } kind()169 inline uint32 kind() const { return m_info.node.kind; } nodeInfo()170 inline const live_node_info& nodeInfo() const { return m_info; } name()171 inline const char* name() const { return m_info.name; } id()172 inline media_node_id id() const { return m_info.node.node; } 173 174 public: // *** member access 175 176 // turn cycle mode (looping) on or off 177 void setCycling( 178 bool cycle); 179 bool isCycling() const; 180 181 // is the node running? 182 bool isRunning() const; 183 184 // was the node created via NodeManager::instantiate()? 185 bool isInternal() const; 186 187 // fetch the group, or 0 if the node is ungrouped. 188 NodeGroup* group() const; 189 190 // flag access 191 uint32 flags() const; 192 void setFlags( 193 uint32 flags); 194 195 // [e.moon 29sep99] 196 // access addon-hint info 197 // - returns B_BAD_VALUE if not an add-on node created by this NodeManager 198 199 status_t getDormantNodeInfo( 200 dormant_node_info* outInfo); 201 202 // [e.moon 29sep99] 203 // access file being played 204 // - returns B_BAD_VALUE if not an add-on node created by this NodeManager, 205 // or if the node has no associated file 206 207 status_t getFile( 208 entry_ref* outFile); 209 210 // [e.moon 8dec99] 211 // set file to play 212 213 status_t setFile( 214 const entry_ref& file, 215 bigtime_t* outDuration=0); //nyi 216 217 // [e.moon 23oct99] 218 // returns true if the media_node has been released (call releaseNode() to 219 // make this happen.) 220 221 bool isNodeReleased() const; 222 223 // now implemented by ObservableHandler [20aug99] 224 // // has this reference been released? 225 // bool isReleased() const; 226 227 public: // *** run-mode operations 228 void setRunMode( 229 uint32 runMode, 230 bigtime_t delay=0LL); 231 uint32 runMode() const; 232 233 bigtime_t recordingDelay() const; 234 235 // calculates the minimum amount of delay needed for 236 // B_RECORDING mode 237 // +++++ 15sep99: returns biggest_output_buffer_duration * 2 238 // +++++ 28sep99: adds downstream latency 239 bigtime_t calculateRecordingModeDelay(); //nyi 240 241 public: // *** connection access 242 243 // connection access: vector versions 244 245 status_t getInputConnections( 246 std::vector<Connection>& ioConnections, 247 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 248 249 status_t getOutputConnections( 250 std::vector<Connection>& ioConnections, 251 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 252 253 // connection access: flat array versions 254 255 status_t getInputConnections( 256 Connection* outConnections, 257 int32 maxConnections, 258 int32* outNumConnections, 259 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 260 261 status_t getOutputConnections( 262 Connection* outConnections, 263 int32 maxConnections, 264 int32* outNumConnections, 265 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 266 267 // +++++ connection matching by source/destination +++++ 268 269 public: // *** position reporting/listening 270 271 bool positionReportsEnabled() const; 272 273 void enablePositionReports(); 274 void disablePositionReports(); 275 276 // Fetch the approximate current position: 277 // Returns the last reported position, and the 278 // performance time at which that position was reached. If the 279 // transport has never been started, the start position and 280 // a performance time of 0 will be returned. If position updating 281 // isn't currently enabled, returns B_NOT_ALLOWED. 282 283 status_t getLastPosition( 284 bigtime_t* outPosition, 285 bigtime_t* outPerfTime) const; 286 287 // Subscribe to regular position reports: 288 // Position reporting isn't rolled into the regular observer 289 // interface because a large number of messages are generated 290 // (the frequency can be changed; see below.) 291 292 status_t addPositionObserver( 293 BHandler* handler); 294 295 status_t removePositionObserver( 296 BHandler* handler); 297 298 // Set how often position updates will be sent: 299 // Realistically, period should be > 10000 or so. 300 301 status_t setPositionUpdatePeriod( 302 bigtime_t period); 303 304 bigtime_t positionUpdatePeriod() const; 305 306 public: // *** BMediaRoster wrappers & convenience methods 307 308 // release the media node 309 // (if allowed, will trigger the release/deletion of this object) 310 status_t releaseNode(); 311 312 // calculate total (internal + downstream) latency for this node 313 314 status_t totalLatency( 315 bigtime_t* outLatency) const; 316 317 318 // retrieve input/output matching the given destination/source. 319 // returns B_MEDIA_BAD_[SOURCE | DESTINATION] if the destination 320 // or source don't correspond to this node. 321 322 status_t findInput( 323 const media_destination& forDestination, 324 media_input* outInput) const; 325 326 status_t findOutput( 327 const media_source& forSource, 328 media_output* outOutput) const; 329 330 331 // endpoint matching (given name and/or format as 'hints'). 332 // If no hints are given, returns the first free endpoint, if 333 // any exist. 334 // returns B_ERROR if no matching endpoint is found. 335 336 status_t findFreeInput( 337 media_input* outInput, 338 media_type type=B_MEDIA_UNKNOWN_TYPE, 339 const char* name=0) const; 340 341 status_t findFreeInput( 342 media_input* outInput, 343 const media_format* format, 344 const char* name=0) const; 345 346 status_t findFreeOutput( 347 media_output* outOutput, 348 media_type type=B_MEDIA_UNKNOWN_TYPE, 349 const char* name=0) const; 350 351 status_t findFreeOutput( 352 media_output* outOutput, 353 const media_format* format, 354 const char* name=0) const; 355 356 // node endpoint access: vector versions (wrappers for BMediaRoster 357 // calls.) 358 359 status_t getFreeInputs( 360 std::vector<media_input>& ioInputs, 361 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 362 363 status_t getConnectedInputs( 364 std::vector<media_input>& ioInputs, 365 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 366 367 status_t getFreeOutputs( 368 std::vector<media_output>& ioOutputs, 369 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 370 371 status_t getConnectedOutputs( 372 std::vector<media_output>& ioOutputs, 373 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 374 375 376 // node endpoint access: array versions (wrappers for BMediaRoster 377 // calls.) 378 379 status_t getFreeInputs( 380 media_input* outInputs, 381 int32 maxInputs, 382 int32* outNumInputs, 383 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 384 385 status_t getConnectedInputs( 386 media_input* outInputs, 387 int32 maxInputs, 388 int32* outNumInputs) const; 389 390 status_t getFreeOutputs( 391 media_output* outOutputs, 392 int32 maxOutputs, 393 int32* outNumOutputs, 394 media_type filterType=B_MEDIA_UNKNOWN_TYPE) const; 395 396 status_t getConnectedOutputs( 397 media_output* outOutputs, 398 int32 maxOutputs, 399 int32* outNumOutputs) const; 400 401 public: // *** BHandler: 402 virtual void MessageReceived( 403 BMessage* message); 404 405 public: // *** IObservable: [20aug99] 406 virtual void observerAdded( 407 const BMessenger& observer); 408 409 virtual void observerRemoved( 410 const BMessenger& observer); 411 412 virtual void notifyRelease(); 413 414 virtual void releaseComplete(); 415 416 protected: // *** ILockable 417 // Only WRITE locking is allowed! 418 419 bool lock( 420 lock_t type=WRITE, 421 bigtime_t timeout=B_INFINITE_TIMEOUT); 422 bool unlock( 423 lock_t type=WRITE); 424 bool isLocked( 425 lock_t type=WRITE) const; 426 427 protected: // *** ctor (accessible to NodeManager) 428 // throws runtime_error 429 NodeRef( 430 const media_node& node, 431 NodeManager* manager, 432 uint32 userFlags, 433 uint32 implFlags); 434 435 protected: // *** endpoint-fixing operations (no lock required) 436 437 // 'fix' (fill in node if needed) sets of inputs/outputs 438 void _fixInputs( 439 media_input* inputs, 440 int32 count) const; 441 void _fixInputs( 442 std::vector<media_input>& inputs) const; 443 444 void _fixOutputs( 445 media_output* outputs, 446 int32 count) const; 447 void _fixOutputs( 448 std::vector<media_output>& outputs) const; 449 450 protected: // *** internal/NodeManager operations (LOCK REQUIRED) 451 452 // call after instantiation to register info used to select and 453 // create this add-on node 454 455 void _setAddonHint( 456 const dormant_node_info* info, 457 const entry_ref* file=0); 458 459 // call to set a new group; if 0, the node must have no 460 // connections 461 void _setGroup( 462 NodeGroup* group); 463 464 // *** NodeGroup API *** 465 // 9aug99: moved from NodeGroup 466 // [e.moon 13oct99] removed inlines for the sake of PPC sanity 467 468 // initialize the given node's transport-state members 469 // (this may be called from the transport thread or from 470 // an API-implementation method.) 471 472 status_t _initTransportState(); 473 474 status_t _setTimeSource( 475 media_node_id timeSourceID); 476 477 status_t _setRunMode( 478 const uint32 runMode, 479 bigtime_t delay=0LL); 480 481 status_t _setRunModeAuto( 482 const uint32 runMode); 483 484 // seek and preroll the given node. 485 // *** this method should not be called from the transport thread 486 // (since preroll operations can block for a relatively long time.) 487 // 488 // returns B_NOT_ALLOWED if the node is running, or if its NO_PREROLL 489 // flag is set; otherwise, returns B_OK on success or a Media Roster 490 // error. 491 492 status_t _preroll( 493 bigtime_t position); 494 495 // seek the given node if possible 496 // (this may be called from the transport thread or from 497 // an API-implementation method.) 498 499 status_t _seek( 500 bigtime_t position, 501 bigtime_t when); 502 503 // seek the given (stopped) node 504 // (this may be called from the transport thread or from 505 // an API-implementation method.) 506 507 status_t _seekStopped( 508 bigtime_t position); 509 510 // start the given node, if possible & necessary, at 511 // the given time 512 // (this may be called from the transport thread or from 513 // an API-implementation method.) 514 515 status_t _start( 516 bigtime_t when); 517 518 // stop the given node (which may or may not still be 519 // a member of this group.) 520 // (this may be called from the transport thread or from 521 // an API-implementation method.) 522 523 status_t _stop(); 524 525 // roll the given node, if possible. 526 // (this may be called from the transport thread or from 527 // an API-implementation method.) 528 529 status_t _roll( 530 bigtime_t start, 531 bigtime_t stop, 532 bigtime_t position); 533 534 // refresh the node's current latency; if I reference 535 // a B_RECORDING node, update its 'producer delay'. 536 537 status_t _updateLatency(); 538 539 // +++++ this method may not be needed 10aug99 +++++ 540 // Figure the earliest time at which the given node can be started. 541 // Also calculates the position at which it should start from to 542 // play in sync with other nodes in the group, if the transport is 543 // running; if stopped, *outPosition will be set to the current 544 // start position. 545 // Pass the estimated amount of time needed to prepare the 546 // node for playback (ie. preroll & a little fudge factor) in 547 // startDelay. 548 // 549 // (this may be called from the transport thread or from 550 // an API-implementation method.) 551 552 status_t _calcStartTime( 553 bigtime_t startDelay, 554 bigtime_t* outTime, 555 bigtime_t* outPosition); //nyi 556 557 // *** Position reporting *** 558 559 // callers: _start(), _roll(), enablePositionReports() 560 status_t _startPositionThread(); 561 562 // callers: _stop(), disablePositionReports(), dtor 563 status_t _stopPositionThread(); 564 565 // [e.moon 14oct99] handle a report 566 status_t _handlePositionUpdate( 567 bigtime_t perfTime, 568 bigtime_t position); 569 570 // callers: _handlePositionUpdate 571 // (schedules a position update for the given time and position; 572 // if the position overlaps a cycle, adjusts time & position 573 // so that the notification is sent at the cycle point.) 574 status_t _schedulePositionUpdate( 575 bigtime_t when, 576 bigtime_t position); 577 578 // callers: _handlePositionUpdate, _initPositionThread() 579 // Send a message to all position observers 580 status_t _notifyPosition( 581 bigtime_t when, 582 bigtime_t position); 583 584 private: // *** members 585 586 // the node manager 587 NodeManager* m_manager; 588 589 // owning (parent) group; may be 0 if node is not connected. 590 // A connected node always has a group, since groups allow transport 591 // operations. New groups are created as necessary. 592 NodeGroup* m_group; 593 594 // the node's state 595 live_node_info m_info; 596 597 // user-definable transport behavior 598 uint32 m_flags; 599 600 // private/implementation flags 601 602 enum impl_flag_t { 603 // the node was created by NodeManager 604 _INTERNAL = 1<<1, 605 // the node should NOT be released when this instance is destroyed 606 _NO_RELEASE = 1<<2, 607 // notification of the node's instantiation has been received 608 // [e.moon 11oct99] 609 _CREATE_NOTIFIED = 1<<3 610 }; 611 612 uint32 m_implFlags; 613 614 // takes BMediaNode::run_mode values or 0 (wildcard: 615 // group run mode used instead) 616 // May not be B_OFFLINE; that must be specified at the group level. 617 618 uint32 m_runMode; 619 620 // only valid if m_runMode is BMediaNode::B_RECORDING 621 bigtime_t m_recordingDelay; 622 623 // Media Roster connection [e.moon 11oct99] 624 bool m_watching; 625 626 // hint information: this info is serialized with the object 627 // to provide 'hints' towards properly finding the same add-on 628 // node later on. If no hint is provided, the node is assumed 629 // to be external to (not created by) the NodeManager. 630 631 struct addon_hint; 632 addon_hint* m_addonHint; 633 634 // * position listening: 635 // - moved from NodeGroup 9aug99 636 637 bool m_positionReportsEnabled; 638 bool m_positionReportsStarted; 639 bigtime_t m_positionUpdatePeriod; 640 static const bigtime_t s_defaultPositionUpdatePeriod = 50000LL; 641 642 ::MultiInvoker m_positionInvoker; 643 644 bigtime_t m_tpLastPositionUpdate; 645 bigtime_t m_lastPosition; 646 647 // * synchronization threads 648 649 // only active if position listening has been enabled 650 NodeSyncThread* m_positionThread; 651 652 // // only active if this node is cycling (looping) 653 // CycleSyncThread* m_cycleSyncThread; 654 // +++++ 10aug99: moved back to NodeGroup 655 656 private: // *** transport state members 657 658 // is this node running? 659 bool m_running; 660 661 // has the media_node (NOT this object) been released? 662 bool m_nodeReleased; 663 664 // is this node supposed to loop? 665 bool m_cycle; 666 667 // has the node been prepared to start? 668 bool m_prerolled; 669 670 // when was the node started? 671 bigtime_t m_tpStart; 672 673 // if the node has been prerolled, m_tpLastSeek will be 0 but 674 // m_lastSeekPos will reflect the node's prerolled position 675 676 bigtime_t m_tpLastSeek; 677 bigtime_t m_lastSeekPos; 678 679 // has a stop event been queued? [e.moon 11oct99] 680 bigtime_t m_stopQueued; 681 682 // last known latency for this node 683 bigtime_t m_latency; 684 }; 685 686 __END_CORTEX_NAMESPACE 687 #endif /*__NodeRef_H__*/ 688