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