xref: /haiku/src/apps/cortex/NodeManager/NodeRef.h (revision c90684742e7361651849be4116d0e5de3a817194)
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