btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / cortex / NodeManager / NodeManager.h
blob51abcf9fd7ac6be75fe915743fbeedb56bd7d49a
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
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.
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.
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.
32 // NodeManager.h (Cortex)
34 // * PURPOSE
35 // Provides a Media Kit application with a straightforward
36 // way to keep track of media nodes and the connections
37 // between them. Nodes are collected into sets via the
38 // NodeGroup class; these sets can be controlled in tandem.
40 // * GROUPING NOTES
41 // A new group is created with the following information:
42 // - time source (defaults to the DAC time source)
43 // - a user-provided name
45 // New nodes can be added to a group via NodeGroup methods. When a
46 // node is added to a group, it will automatically be assigned the
47 // group's time source. Unless the node has a run mode set, it will
48 // also be assigned the group's run mode. (If the group is in B_OFFLINE
49 // mode, this will be assigned to all nodes even if they specify something
50 // else.) If a node is added to a group whose transport is running, it
51 // will automatically be seeked and started (unless one or both of those
52 // operations has been disabled.)
53 //
54 // * SYNCHRONIZATION NOTES
55 // Each NodeManager object, including all the NodeGroup and NodeRef
56 // objects in its care, is synchronized by a single semaphore.
57 // Most operations in these three classes require that the object
58 // be locked.
60 // * UI HOOKS
61 // NodeManager resends any Media Roster messages to all observers
62 // *after* processing them: the NodeRef corresponding to a newly-
63 // created node, for example, must exist by the time that a
64 // NodeManager observer receives B_MEDIA_NODE_CREATED.
67 // * HISTORY
68 // e.moon 7nov99 1) added hooks for Media Roster message processing
69 // 2) improved NodeGroup handling
70 // e.moon 6nov99 safe node instantiation (via addon-host
71 // application)
72 // e.moon 11aug99 Expanded findConnection() methods.
73 // e.moon 6jul99 Begun
75 #ifndef __NodeManager_H__
76 #define __NodeManager_H__
78 #include "ILockable.h"
79 #include "ObservableLooper.h"
80 #include "observe.h"
82 #include <Looper.h>
83 #include <MediaDefs.h>
84 #include <MediaNode.h>
86 #include <vector>
87 #include <map>
89 class BMediaRoster;
91 #include "cortex_defs.h"
92 __BEGIN_CORTEX_NAMESPACE
94 class Connection;
95 class NodeGroup;
96 class NodeRef;
98 class NodeManager :
99 public ObservableLooper,
100 public ILockable {
102 // primary parent class:
103 typedef ObservableLooper _inherited;
105 friend class NodeGroup;
106 friend class NodeRef;
107 friend class Connection;
109 public: // *** messages
110 // [13aug99]
111 // NodeManager retransmits Media Roster messages to its listeners,
112 // after processing each message.
114 /// B_MEDIA_CONNECTION_BROKEN
115 // This message, as sent by the Media Roster, contains only
116 // source/destination information. NodeManager adds these fields
117 // to the message:
118 // __connection_id: (uint32) id of the Connection; 0 if no
119 // matching Connection was found.
120 // __source_node_id: media_node_id of the node corresponding to
121 // the source; 0 if no matching Connection was
122 // found.
123 // __destination_node_id: media_node_id of the node corresponding to
124 // the source; 0 if no matching Connection was
125 // found.
127 // B_MEDIA_FORMAT_CHANGED
128 // NodeManager add these fields as above:
129 // __connection_id
130 // __source_node_id
131 // __destination_node_id
133 enum outbound_message_t {
134 M_OBSERVER_ADDED =NodeManager_message_base,
135 M_OBSERVER_REMOVED,
136 M_RELEASED,
138 // groupID: int32
139 M_GROUP_CREATED,
140 M_GROUP_DELETED,
142 // groupID: int32 x2 (the first is the original)
143 M_GROUP_SPLIT,
145 // groupID: int32 x2
146 M_GROUPS_MERGED
149 public: // *** default group names
151 static const char* const s_defaultGroupPrefix;
152 static const char* const s_timeSourceGroup;
153 static const char* const s_audioInputGroup;
154 static const char* const s_videoInputGroup;
155 static const char* const s_audioMixerGroup;
156 static const char* const s_videoOutputGroup;
158 public: // *** hooks
160 // [e.moon 7nov99] these hooks are called during processing of
161 // BMediaRoster messages, before any notification is sent to
162 // observers. For example, if a B_MEDIA_NODES_CREATED message
163 // were received describing 3 new nodes, nodeCreated() would be
164 // called 3 times before the notification was sent.
166 virtual void nodeCreated(
167 NodeRef* ref);
169 virtual void nodeDeleted(
170 const NodeRef* ref);
172 virtual void connectionMade(
173 Connection* connection);
175 virtual void connectionBroken(
176 const Connection* connection);
178 virtual void connectionFailed(
179 const media_output & output,
180 const media_input & input,
181 const media_format & format,
182 status_t error);
184 public: // *** ctor/dtor
186 NodeManager(
187 bool useAddOnHost=false);
189 // don't directly delete NodeManager;
190 // use IObservable::release()
191 virtual ~NodeManager();
193 public: // *** const members
195 // cached roster pointer
196 ::BMediaRoster* const roster;
198 public: // *** operations
200 // * ACCESS
202 // fetches NodeRef corresponding to a given ID; returns
203 // B_BAD_VALUE if no matching entry was found (and writes
204 // a 0 into the provided pointer.)
206 status_t getNodeRef(
207 media_node_id id,
208 NodeRef** outRef) const;
210 // [13aug99]
211 // fetches Connection corresponding to a given source/destination
212 // on a given node. Returns an invalid connection and B_BAD_VALUE
213 // if no matching connection was found.
215 status_t findConnection(
216 media_node_id node,
217 const media_source& source,
218 Connection* outConnection) const;
220 status_t findConnection(
221 media_node_id node,
222 const media_destination& destination,
223 Connection* outConnection) const;
225 // [e.moon 28sep99]
226 // fetches a Connection matching the given source and destination
227 // nodes. Returns an invalid connection and B_BAD_VALUE if
228 // no matching connection was found
230 status_t findConnection(
231 media_node_id sourceNode,
232 media_node_id destinationNode,
233 Connection* outConnection) const;
235 // [e.moon 28sep99]
236 // tries to find a route from 'nodeA' to 'nodeB'; returns
237 // true if one exists, false if not. If nodeA and nodeB
238 // are the same node, only returns true if it's actually
239 // connected to itself.
241 bool findRoute(
242 media_node_id nodeA,
243 media_node_id nodeB);
245 private:
246 // implementation of above
247 class _find_route_state;
248 bool _find_route_recurse(
249 NodeRef* origin,
250 media_node_id target,
251 _find_route_state* state);
253 public:
254 // fetches Connection corresponding to a given source or
255 // destination; Returns an invalid connection and B_BAD_VALUE if
256 // none found.
257 // * Note: this is the slowest possible way to look up a
258 // connection. Since the low-level source/destination
259 // structures don't include a node ID, and a destination
260 // port can differ from its node's control port, a linear
261 // search of all known connections is performed. Only
262 // use these methods if you have no clue what node the
263 // connection corresponds to.
265 status_t findConnection(
266 const media_source& source,
267 Connection* outConnection) const;
269 status_t findConnection(
270 const media_destination& destination,
271 Connection* outConnection) const;
273 // fetch NodeRefs for system nodes (if a particular node doesn't
274 // exist, these methods return 0)
276 NodeRef* audioInputNode() const;
277 NodeRef* videoInputNode() const;
278 NodeRef* audioMixerNode() const;
279 NodeRef* audioOutputNode() const;
280 NodeRef* videoOutputNode() const;
282 // * GROUP CREATION
284 NodeGroup* createGroup(
285 const char* name,
286 BMediaNode::run_mode runMode=BMediaNode::B_INCREASE_LATENCY);
288 // fetch groups by index
289 // - you can write-lock the manager during sets of calls to these methods;
290 // this ensures that the group set won't change. The methods do lock
291 // the group internally, so locking isn't explicitly required.
293 uint32 countGroups() const;
294 NodeGroup* groupAt(
295 uint32 index) const;
297 // look up a group by unique ID; returns B_BAD_VALUE if no
298 // matching group was found
300 status_t findGroup(
301 uint32 id,
302 NodeGroup** outGroup) const;
304 // look up a group by name; returns B_NAME_NOT_FOUND if
305 // no group matching the name was found.
307 status_t findGroup(
308 const char* name,
309 NodeGroup** outGroup) const;
311 // merge the given source group to the given destination;
312 // empties and releases the source group
314 status_t mergeGroups(
315 NodeGroup* sourceGroup,
316 NodeGroup* destinationGroup);
318 // [e.moon 28sep99]
319 // split group: given two nodes currently in the same group
320 // that are not connected (directly OR indirectly),
321 // this method removes outsideNode, and all nodes connected
322 // to outsideNode, from the common group. These nodes are
323 // then added to a new group, returned in 'outGroup'. The
324 // new group has " split" appended to the end of the original
325 // group's name.
327 // Returns B_NOT_ALLOWED if any of the above conditions aren't
328 // met (ie. the nodes are in different groups or an indirect
329 // route exists from one to the other), or B_OK if the group
330 // was split successfully.
332 status_t splitGroup(
333 NodeRef* insideNode,
334 NodeRef* outsideNode,
335 NodeGroup** outGroup);
337 // * INSTANTIATION & CONNECTION
338 // Use these calls rather than the associated BMediaRoster()
339 // methods to assure that the nodes and connections you set up
340 // can be properly serialized & reconstituted.
342 // basic BMediaRoster::InstantiateDormantNode() wrapper
343 // - writes a 0 into *outRef if the instantiation fails
344 // - [e.moon 23oct99]
345 // returns B_BAD_INDEX if InstantiateDormantNode() returns
346 // success, but doesn't hand back a viable media_node
347 // - [e.moon 6nov99] +++++ 'distributed' instantiate:
348 // wait for an external app to create the node; allow for
349 // failure.
351 status_t instantiate(
352 const dormant_node_info& info,
353 NodeRef** outRef=0,
354 bigtime_t timeout=B_INFINITE_TIMEOUT,
355 uint32 nodeFlags=0);
357 // SniffRef/Instantiate.../SetRefFor: a one-call interface
358 // to create a node capable of playing a given media file.
359 // - writes a 0 into *outRef if the instantiation fails; on the
360 // other hand, if instantiation succeeds, but SetRefFor() fails,
361 // a NodeRef will still be returned.
363 status_t instantiate(
364 const entry_ref& file,
365 uint64 requireNodeKinds,
366 NodeRef** outRef,
367 bigtime_t timeout=B_INFINITE_TIMEOUT,
368 uint32 nodeFlags=0,
369 bigtime_t* outDuration=0);
371 // use this method to reference nodes created within your
372 // application. These nodes can't be automatically reconstituted
373 // by the cortex serializer yet.
375 status_t reference(
376 BMediaNode* node,
377 NodeRef** outRef,
378 uint32 nodeFlags=0);
380 // the most flexible form of connect(): set the template
381 // format as you would for BMediaRoster::Connect().
383 status_t connect(
384 const media_output& output,
385 const media_input& input,
386 const media_format& templateFormat,
387 Connection* outConnection=0);
389 // format-guessing form of connect(): tries to find
390 // a common format between output & input before connection;
391 // returns B_MEDIA_BAD_FORMAT if no common format type found.
393 // NOTE: the specifics of the input and output formats are ignored;
394 // this method only looks at the format type, and properly
395 // handles wildcards at that level (B_MEDIA_NO_TYPE).
397 status_t connect(
398 const media_output& output,
399 const media_input& input,
400 Connection* outConnection=0);
402 // disconnects the connection represented by the provided
403 // Connection object. if successful, returns B_OK.
405 status_t disconnect(
406 const Connection& connection);
408 public: // *** node/connection iteration
409 // *** MUST BE LOCKED for any of these calls
411 // usage:
412 // For the first call, pass 'cookie' a pointer to a void* set to 0.
413 // Returns B_BAD_INDEX when the set of nodes has been exhausted (and
414 // invalidates the cookie, so don't try to use it after this point.)
416 status_t getNextRef(
417 NodeRef** outRef,
418 void** cookie);
420 // if you want to stop iterating, call this method to avoid leaking
421 // memory
422 void disposeRefCookie(
423 void** cookie);
425 status_t getNextConnection(
426 Connection* outConnection,
427 void** cookie);
429 void disposeConnectionCookie(
430 void** cookie);
432 public: // *** BHandler impl
433 void MessageReceived(BMessage* message); //nyi
435 public: // *** IObservable hooks
436 virtual void observerAdded(
437 const BMessenger& observer);
439 virtual void observerRemoved(
440 const BMessenger& observer);
442 virtual void notifyRelease();
444 virtual void releaseComplete();
447 public: // *** ILockable impl.
448 virtual bool lock(
449 lock_t type=WRITE,
450 bigtime_t timeout=B_INFINITE_TIMEOUT);
452 virtual bool unlock(
453 lock_t type=WRITE);
455 virtual bool isLocked(
456 lock_t type=WRITE) const;
459 protected: // *** internal operations (LOCK REQUIRED)
462 void _initCommonNodes();
464 void _addRef(
465 NodeRef* ref);
466 void _removeRef(
467 media_node_id id);
469 // create, add, return a NodeRef for the given external node;
470 // must not already exist
471 NodeRef* _addRefFor(
472 const media_node& node,
473 uint32 nodeFlags,
474 uint32 nodeImplFlags=0);
476 void _addConnection(
477 Connection* connection);
478 void _removeConnection(
479 const Connection& connection);
481 void _addGroup(
482 NodeGroup* group);
483 void _removeGroup(
484 NodeGroup* group);
486 // dtor helpers
487 inline void _clearGroup(
488 NodeGroup* group);
490 inline void _freeConnection(
491 Connection* connection);
493 // message handlers
495 // now returns B_OK iff the message should be relayed to observers
496 // [e.moon 11oct99]
497 inline status_t _handleNodesCreated(
498 BMessage* message);
500 inline void _handleNodesDeleted(
501 BMessage* message);
503 inline void _handleConnectionMade(
504 BMessage* message);
506 inline void _handleConnectionBroken(
507 BMessage* message);
509 inline void _handleFormatChanged(
510 BMessage* message);
511 // return flags appropriate for an external
512 // node with the given 'kind'
514 inline uint32 _userFlagsForKind(
515 uint32 kind);
517 inline uint32 _implFlagsForKind(
518 uint32 kind);
520 // [e.moon 28sep99] latency updating
521 // These methods must set the recording-mode delay for
522 // any B_RECORDING nodes they handle.
524 // +++++ abstract to 'for each' and 'for each from'
525 // methods (template or callback?)
528 // refresh cached latency for every node in the given group
529 // (or all nodes if no group given.)
531 inline void _updateLatencies(
532 NodeGroup* group =0);
534 // refresh cached latency for every node attached to
535 // AND INCLUDING the given origin node.
536 // if 'recurse' is true, affects indirectly attached
537 // nodes as well.
539 inline void _updateLatenciesFrom(
540 NodeRef* origin,
541 bool recurse =false);
543 // a bit of unpleasantness [e.moon 13oct99]
544 inline void _lockAllGroups();
545 inline void _unlockAllGroups();
547 private: // *** internal messages
548 enum int_message_t {
549 // groupID: int32
550 _M_GROUP_RELEASED = NodeManager_int_message_base
553 private: // *** members
554 // the main NodeRef store
555 typedef std::map<media_node_id, NodeRef*> node_ref_map;
556 node_ref_map m_nodeRefMap;
558 // the Connection stores (connections are indexed by both
559 // source and destination node ID)
560 typedef std::multimap<media_node_id, Connection*> con_map;
561 con_map m_conSourceMap;
562 con_map m_conDestinationMap;
564 // the NodeGroup store
565 typedef std::vector<NodeGroup*> node_group_set;
566 node_group_set m_nodeGroupSet;
568 // common system nodes
569 NodeRef* m_audioInputNode;
570 NodeRef* m_videoInputNode;
571 NodeRef* m_audioMixerNode;
572 NodeRef* m_audioOutputNode;
573 NodeRef* m_videoOutputNode;
575 // next unique connection ID
576 uint32 m_nextConID;
578 // false until the first 'nodes created' message is
579 // received from the Media Roster, and pre-existing connection
580 // info is filled in:
581 bool m_existingNodesInit;
583 // true if nodes should be launched via an external application
584 // (using AddOnHost)
585 bool m_useAddOnHost;
588 __END_CORTEX_NAMESPACE
589 #endif /*__NodeManager_H__*/