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