xref: /haiku/src/apps/cortex/NodeManager/NodeManager.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 // NodeManager.cpp
2 
3 #include "NodeManager.h"
4 
5 #include "AddOnHost.h"
6 #include "Connection.h"
7 #include "NodeGroup.h"
8 #include "NodeRef.h"
9 
10 #include <Debug.h>
11 #include <MediaRoster.h>
12 
13 #include <algorithm>
14 #include <cstring>
15 #include <functional>
16 #include <list>
17 #include <set>
18 
19 #include "set_tools.h"
20 #include "functional_tools.h"
21 
22 #include "node_manager_impl.h"
23 
24 using namespace std;
25 
26 __USE_CORTEX_NAMESPACE
27 
28 #define D_METHOD(x) //PRINT (x)
29 #define D_MESSAGE(x) //PRINT (x)
30 #define D_ROSTER(x) //PRINT (x)
31 #define D_LOCK(x) //PRINT (x)
32 
33 // -------------------------------------------------------- //
34 // messaging constants
35 // -------------------------------------------------------- //
36 
37 // B_MEDIA_CONNECTION_BROKEN
38 const char* const _connectionField = "__connection_id";
39 const char* const _sourceNodeField = "__source_node_id";
40 const char* const _destNodeField = "__destination_node_id";
41 
42 
43 
44 
45 // -------------------------------------------------------- //
46 // *** hooks
47 // -------------------------------------------------------- //
48 
49 // [e.moon 7nov99] these hooks are called during processing of
50 // BMediaRoster messages, before any notification is sent to
51 // observers.  For example, if a B_MEDIA_NODES_CREATED message
52 // were received describing 3 new nodes, nodeCreated() would be
53 // called 3 times before the notification was sent.
54 
55 void NodeManager::nodeCreated(
56 	NodeRef*											ref) {}
57 
58 void NodeManager::nodeDeleted(
59 	const NodeRef*								ref) {}
60 
61 void NodeManager::connectionMade(
62 	Connection*										connection) {}
63 
64 void NodeManager::connectionBroken(
65 	const Connection*							connection) {}
66 
67 void NodeManager::connectionFailed(
68 	const media_output &							output,
69 	const media_input &								input,
70 	const media_format &							format,
71 	status_t error) {}
72 
73 // -------------------------------------------------------- //
74 // helpers
75 // -------------------------------------------------------- //
76 
77 class _for_each_state {
78 public:
79 	// marks nodes visited
80 	set<media_node_id>		visited;
81 };
82 
83 // [e.moon 28sep99] graph crawling
84 // - does NOT apply operation to origin node.
85 // - if inGroup is non-0, visits only nodes in that group.
86 //
87 // [e.moon 13oct99]: no longer supports locking (use _lockAllGroups() to
88 // be sure all nodes are locked, if necessary.)
89 
90 template<class Op>
91 void _do_for_each_connected(
92 	NodeManager*											manager,
93 	NodeRef*													origin,
94 	NodeGroup*												inGroup,
95 	bool															recurse,
96 	Op																operation,
97 	_for_each_state*									state) {
98 
99 //	PRINT(("### _do_for_each_connected()\n"));
100 
101 	ASSERT(manager->IsLocked());
102 
103 	ASSERT(origin);
104 	ASSERT(state);
105 	status_t err;
106 
107 	if(state->visited.find(origin->id()) != state->visited.end()) {
108 //		PRINT(("### already visited\n"));
109 		// already visited
110 		return;
111 	}
112 
113 	// used to walk connections
114 	vector<Connection>		connections;
115 
116 	// mark visited
117 	state->visited.insert(origin->id());
118 
119 	// walk input connections
120 	origin->getInputConnections(connections);
121 	for(uint32 n = 0; n < connections.size(); ++n) {
122 
123 		if(!connections[n].isValid())
124 			continue;
125 
126 //		PRINT(("# source: %ld\n", connections[n].sourceNode()));
127 
128 		NodeRef* targetRef;
129 		err = manager->getNodeRef(
130 			connections[n].sourceNode(),
131 			&targetRef);
132 		ASSERT(err == B_OK);
133 		ASSERT(targetRef);
134 
135 		if(inGroup && targetRef->group() != inGroup) {
136 //			PRINT(("# .group mismatch\n"));
137 			// don't need to visit
138 			return;
139 		}
140 
141 		// invoke operation
142 //		if(lockRef)
143 //			targetRef->lock();
144 		operation(targetRef);
145 //		if(lockRef)
146 //			targetRef->unlock();
147 
148 		// recurse?
149 		if(recurse)
150 			_do_for_each_connected(
151 				manager,
152 				targetRef,
153 				inGroup,
154 				true,
155 				operation,
156 				state);
157 	}
158 
159 	// walk output connections
160 	connections.clear();
161 	origin->getOutputConnections(connections);
162 	for(uint32 n = 0; n < connections.size(); ++n) {
163 //		PRINT(("# dest: %ld\n", connections[n].destinationNode()));
164 
165 		if(!connections[n].isValid())
166 			continue;
167 
168 		NodeRef* targetRef;
169 		err = manager->getNodeRef(
170 			connections[n].destinationNode(),
171 			&targetRef);
172 		ASSERT(err == B_OK);
173 		ASSERT(targetRef);
174 
175 		if(inGroup && targetRef->group() != inGroup) {
176 //			PRINT(("# .group mismatch\n"));
177 			// don't need to visit
178 			return;
179 		}
180 
181 		// invoke operation
182 //		if(lockRef)
183 //			targetRef->lock();
184 		operation(targetRef);
185 //		if(lockRef)
186 //			targetRef->unlock();
187 
188 		// recurse?
189 		if(recurse)
190 			_do_for_each_connected(
191 				manager,
192 				targetRef,
193 				inGroup,
194 				true,
195 				operation,
196 				state);
197 	}
198 }
199 
200 // dtor helpers
201 inline void NodeManager::_clearGroup(
202 	NodeGroup*										group) {
203 	Autolock _l(group);
204 	D_METHOD((
205 		"NodeManager::_clearGroup()\n"));
206 
207 	// stop group before clearing [10aug99]
208 	group->_stop();
209 
210 	int32 n;
211 	while((n = group->countNodes()) > 0) {
212 		group->removeNode(n-1);
213 	}
214 
215 //	// [e.moon 7nov99] release the group
216 //	status_t err = remove_observer(this, group);
217 //	if(err < B_OK) {
218 //		// spew diagnostics
219 //		PRINT((
220 //			"!!! NodeManager::_clearGroup(): remove_observer(group %ld):\n"
221 //			"    %s\n",
222 //			group->id(),
223 //			strerror(err)));
224 //	}
225 }
226 
227 inline void NodeManager::_freeConnection(
228 	Connection*										connection) {
229 	ASSERT(connection);
230 
231 	D_METHOD((
232 		"NodeManager::_freeConnection(%ld)\n", connection->id()));
233 	status_t err;
234 
235 	// break if internal & still valid
236 	if(
237 		connection->isValid() &&
238 		connection->flags() & Connection::INTERNAL &&
239 		!(connection->flags() & Connection::LOCKED)) {
240 
241 		D_METHOD((
242 			"! breaking connection:\n"
243 			"  source node:  %ld\n"
244 			"  source id:    %ld\n"
245 			"  source port:  %ld\n"
246 			"  dest node:    %ld\n"
247 			"  dest id:      %ld\n"
248 			"  dest port:    %ld\n",
249 			connection->sourceNode(),
250 			connection->source().id, connection->source().port,
251 			connection->destinationNode(),
252 			connection->destination().id, connection->destination().port));
253 
254 		// do it
255 		D_ROSTER(("# roster->Disconnect()\n"));
256 		err = roster->Disconnect(
257 			connection->sourceNode(),
258 			connection->source(),
259 			connection->destinationNode(),
260 			connection->destination());
261 
262 		if(err < B_OK) {
263 			D_METHOD((
264 				"!!! BMediaRoster::Disconnect('%s' -> '%s') failed:\n"
265 				"    %s\n",
266 				connection->outputName(), connection->inputName(),
267 				strerror(err)));
268 		}
269 	}
270 
271 	// delete
272 	delete connection;
273 }
274 
275 // -------------------------------------------------------- //
276 // *** ctor/dtor
277 // -------------------------------------------------------- //
278 
279 
280 NodeManager::~NodeManager() {
281 	D_METHOD((
282 		"~NodeManager()\n"));
283 	ASSERT(IsLocked());
284 
285 	// make a list of nodes to be released
286 	list<NodeRef*> deadNodes;
287 
288 	for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
289 		it != m_nodeRefMap.end(); ++it) {
290 		deadNodes.push_back((*it).second);
291 	}
292 
293 	// ungroup all nodes
294 
295 // [e.moon 13oct99] making PPC compiler happy
296 //	for_each(
297 //		m_nodeGroupSet.begin(),
298 //		m_nodeGroupSet.end(),
299 //		bound_method(
300 //			*this,
301 //			&NodeManager::_clearGroup
302 //		)
303 //	);
304 	for(node_group_set::iterator it = m_nodeGroupSet.begin();
305 		it != m_nodeGroupSet.end(); ++it) {
306 		_clearGroup(*it);
307 	}
308 
309 	// delete groups
310 	ptr_set_delete(
311 		m_nodeGroupSet.begin(),
312 		m_nodeGroupSet.end());
313 	m_nodeGroupSet.clear();
314 
315 
316 	// deallocate all connections; disconnect internal nodes
317 // [e.moon 13oct99] making PPC compiler happy
318 //	for_each(
319 //		m_conSourceMap.begin(),
320 //		m_conSourceMap.end(),
321 //		unary_map_function(
322 //			m_conSourceMap,
323 //			bound_method(
324 //				*this,
325 //				&NodeManager::_freeConnection
326 //			)
327 //		)
328 //	);
329 	for(con_map::iterator it = m_conSourceMap.begin();
330 		it != m_conSourceMap.end(); ++it) {
331 		_freeConnection((*it).second);
332 	}
333 	m_conSourceMap.clear();
334 	m_conDestinationMap.clear();
335 
336 	// release all nodes
337 	for(list<NodeRef*>::const_iterator it = deadNodes.begin();
338 		it != deadNodes.end(); ++it) {
339 		(*it)->release();
340 	}
341 
342 	if(m_nodeRefMap.size()) {
343 		// +++++ nodes will only remain if they have observers; cope!
344 		PRINT(("*** %ld nodes remaining!\n", m_nodeRefMap.size()));
345 
346 		deadNodes.clear();
347 		for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
348 			it != m_nodeRefMap.end(); ++it)
349 				deadNodes.push_back((*it).second);
350 
351 		ptr_set_delete(
352 			deadNodes.begin(),
353 			deadNodes.end());
354 	}
355 
356 //	for_each(
357 //		m_nodeRefMap.begin(),
358 //		m_nodeRefMap.end(),
359 //		unary_map_function(
360 //			m_nodeRefMap,
361 //			mem_fun(
362 //				&NodeRef::release
363 //			)
364 //		)
365 //	);
366 //
367 //	// delete all nodes
368 //	ptr_map_delete(
369 //		m_nodeRefMap.begin(),
370 //		m_nodeRefMap.end());
371 //
372 //
373 //	PRINT((
374 //		"~NodeManager() done\n"));
375 //
376 }
377 
378 const char* const			NodeManager::s_defaultGroupPrefix = "No Name";
379 const char* const			NodeManager::s_timeSourceGroup = "Time Sources";
380 const char* const			NodeManager::s_audioInputGroup = "System Audio Input";
381 const char* const			NodeManager::s_videoInputGroup = "System Video Input";
382 const char* const			NodeManager::s_audioMixerGroup = "System Audio Mixer";
383 const char* const			NodeManager::s_videoOutputGroup = "System Video Output";
384 
385 NodeManager::NodeManager(
386 	bool													useAddOnHost) :
387 
388 	ObservableLooper("NodeManager"),
389 	roster(BMediaRoster::Roster()),
390 	m_audioInputNode(0),
391 	m_videoInputNode(0),
392 	m_audioMixerNode(0),
393 	m_audioOutputNode(0),
394 	m_videoOutputNode(0),
395 	m_nextConID(1),
396 	m_existingNodesInit(false),
397 	m_useAddOnHost(useAddOnHost) {
398 
399 	D_METHOD((
400 		"NodeManager()\n"));
401 
402 	ASSERT(roster);
403 
404 	// create refs for common nodes
405 	_initCommonNodes();
406 
407 	// start the looper
408 	Run();
409 
410 	// initialize connection to the media roster
411 	D_ROSTER(("# roster->StartWatching(%p)\n", this));
412 	roster->StartWatching(BMessenger(this));
413 }
414 
415 // -------------------------------------------------------- //
416 // *** operations
417 // -------------------------------------------------------- //
418 
419 // * ACCESS
420 
421 // fetches NodeRef corresponding to a given ID; returns
422 // B_BAD_VALUE if no matching entry was found (and writes
423 // a 0 into the provided pointer.)
424 
425 status_t NodeManager::getNodeRef(
426 	media_node_id									id,
427 	NodeRef**											outRef) const {
428 	Autolock _l(this);
429 
430 	D_METHOD((
431 		"NodeManager::getNodeRef(%ld)\n", id));
432 
433 	node_ref_map::const_iterator it = m_nodeRefMap.find(id);
434 	if(it == m_nodeRefMap.end()) {
435 		*outRef = 0;
436 		return B_BAD_VALUE;
437 	}
438 
439 	*outRef = (*it).second;
440 	return B_OK;
441 }
442 
443 // [13aug99]
444 // fetches Connection corresponding to a given source/destination
445 // on a given node.  Returns an invalid connection and B_BAD_VALUE
446 // if no matching connection was found.
447 
448 status_t NodeManager::findConnection(
449 	media_node_id									node,
450 	const media_source&						source,
451 	Connection*										outConnection) const {
452 	Autolock _l(this);
453 
454 	D_METHOD((
455 		"NodeManager::findConnection()\n"));
456 	ASSERT(source != media_source::null);
457 
458 	con_map::const_iterator it = m_conSourceMap.lower_bound(node);
459 	con_map::const_iterator itEnd = m_conSourceMap.upper_bound(node);
460 	for(; it != itEnd; ++it)
461 		if((*it).second->source() == source) {
462 			// copy connection
463 			*outConnection = *((*it).second);
464 			return B_OK;
465 		}
466 
467 	*outConnection = Connection();
468 	return B_BAD_VALUE;
469 }
470 
471 status_t NodeManager::findConnection(
472 	media_node_id									node,
473 	const media_destination&			destination,
474 	Connection*										outConnection) const {
475 	Autolock _l(this);
476 
477 	D_METHOD((
478 		"NodeManager::findConnection()\n"));
479 	ASSERT(destination != media_destination::null);
480 
481 	con_map::const_iterator it = m_conDestinationMap.lower_bound(node);
482 	con_map::const_iterator itEnd = m_conDestinationMap.upper_bound(node);
483 	for(; it != itEnd; ++it)
484 		if((*it).second->destination() == destination) {
485 			// copy connection
486 			*outConnection = *((*it).second);
487 			return B_OK;
488 		}
489 
490 	*outConnection = Connection();
491 	return B_BAD_VALUE;
492 }
493 
494 // [e.moon 28sep99]
495 // fetches a Connection matching the given source and destination
496 // nodes.  Returns an invalid connection and B_BAD_VALUE if
497 // no matching connection was found
498 
499 status_t NodeManager::findConnection(
500 	media_node_id									sourceNode,
501 	media_node_id									destinationNode,
502 	Connection*										outConnection) const {
503 	Autolock _l(this);
504 
505 	D_METHOD((
506 		"NodeManager::findConnection(source %ld, dest %ld)\n", sourceNode, destinationNode));
507 
508 	con_map::const_iterator it = m_conSourceMap.lower_bound(sourceNode);
509 	con_map::const_iterator itEnd = m_conSourceMap.upper_bound(sourceNode);
510 	for(; it != itEnd; ++it) {
511 		if((*it).second->destinationNode() == destinationNode) {
512 			*outConnection = *((*it).second);
513 			return B_OK;
514 		}
515 	}
516 
517 	*outConnection = Connection();
518 	return B_BAD_VALUE;
519 }
520 
521 // [e.moon 28sep99]
522 // tries to find a route from 'nodeA' to 'nodeB'; returns
523 // true if one exists, false if not.
524 
525 class NodeManager::_find_route_state {
526 public:
527 	set<media_node_id>						visited;
528 };
529 
530 bool NodeManager::findRoute(
531 	media_node_id									nodeA,
532 	media_node_id									nodeB) {
533 	Autolock _l(this);
534 
535 	D_METHOD((
536 		"NodeManager::findRoute(%ld, %ld)\n", nodeA, nodeB));
537 	status_t err;
538 
539 	NodeRef* ref;
540 	err = getNodeRef(nodeA, &ref);
541 	if(err < B_OK) {
542 		PRINT((
543 			"!!! NodeManager::findRoute(%ld, %ld): no ref for node %ld\n",
544 			nodeA, nodeB, nodeA));
545 		return false;
546 	}
547 
548 	_find_route_state st;
549 	return _find_route_recurse(ref, nodeB, &st);
550 }
551 
552 // implementation of above
553 
554 bool NodeManager::_find_route_recurse(
555 	NodeRef*													origin,
556 	media_node_id											target,
557 	_find_route_state*								state) {
558 
559 	ASSERT(IsLocked());
560 	ASSERT(origin);
561 	ASSERT(state);
562 	status_t err;
563 
564 	// node already visited?
565 	if(state->visited.find(origin->id()) != state->visited.end()) {
566 		return false;
567 	}
568 
569 	// mark node visited
570 	state->visited.insert(origin->id());
571 
572 	vector<Connection> connections;
573 
574 	// walk input connections
575 	origin->getInputConnections(connections);
576 	for(uint32 n = 0; n < connections.size(); ++n) {
577 
578 		if(!connections[n].isValid())
579 			continue;
580 
581 		// test against target
582 		if(connections[n].sourceNode() == target)
583 			return true; // SUCCESS
584 
585 		// recurse
586 		NodeRef* ref;
587 		err = getNodeRef(
588 			connections[n].sourceNode(),
589 			&ref);
590 		ASSERT(err == B_OK);
591 		ASSERT(ref);
592 
593 		if(_find_route_recurse(
594 			ref,
595 			target,
596 			state))
597 			return true; // SUCCESS
598 	}
599 
600 	// walk output connections
601 	connections.clear();
602 	origin->getOutputConnections(connections);
603 	for(uint32 n = 0; n < connections.size(); ++n) {
604 
605 		if(!connections[n].isValid())
606 			continue;
607 
608 		// test against target
609 		if(connections[n].destinationNode() == target)
610 			return true; // SUCCESS
611 
612 		// recurse
613 		NodeRef* ref;
614 		err = getNodeRef(
615 			connections[n].destinationNode(),
616 			&ref);
617 		ASSERT(err == B_OK);
618 		ASSERT(ref);
619 
620 		if(_find_route_recurse(
621 			ref,
622 			target,
623 			state))
624 			return true; // SUCCESS
625 	}
626 
627 	return false; // FAILED
628 }
629 
630 
631 
632 // fetches Connection corresponding to a given source or
633 // destination; Returns an invalid connection and B_BAD_VALUE if
634 // none found.
635 // * Note: this is the slowest possible way to look up a
636 //   connection.  Since the low-level source/destination
637 //   structures don't include a node ID, and a destination
638 //   port can differ from its node's control port, a linear
639 //   search of all known connections is performed.  Only
640 //   use these methods if you have no clue what node the
641 //   connection corresponds to.
642 
643 status_t NodeManager::findConnection(
644 	const media_source&						source,
645 	Connection*										outConnection) const {
646 	Autolock _l(this);
647 
648 	D_METHOD((
649 		"NodeManager::findConnection()\n"));
650 	ASSERT(source != media_source::null);
651 
652 	for(con_map::const_iterator it = m_conSourceMap.begin();
653 		it != m_conSourceMap.end(); ++it) {
654 		if((*it).second->source() == source) {
655 			// copy connection
656 			*outConnection = *((*it).second);
657 			return B_OK;
658 		}
659 	}
660 
661 	*outConnection = Connection();
662 	return B_BAD_VALUE;
663 }
664 
665 status_t NodeManager::findConnection(
666 	const media_destination&			destination,
667 	Connection*										outConnection) const {
668 	Autolock _l(this);
669 
670 	D_METHOD((
671 		"NodeManager::findConnection()\n"));
672 	ASSERT(destination != media_destination::null);
673 
674 	for(con_map::const_iterator it = m_conDestinationMap.begin();
675 		it != m_conDestinationMap.end(); ++it) {
676 		if((*it).second->destination() == destination) {
677 			// copy connection
678 			*outConnection = *((*it).second);
679 			return B_OK;
680 		}
681 	}
682 
683 	*outConnection = Connection();
684 	return B_BAD_VALUE;
685 }
686 
687 
688 // fetch NodeRefs for system nodes (if a particular node doesn't
689 // exist, these methods return 0)
690 
691 NodeRef* NodeManager::audioInputNode() const {
692 	Autolock _l(this);
693 	return m_audioInputNode;
694 }
695 NodeRef* NodeManager::videoInputNode() const {
696 	Autolock _l(this);
697 	return m_videoInputNode;
698 }
699 NodeRef* NodeManager::audioMixerNode() const {
700 	Autolock _l(this);
701 	return m_audioMixerNode;
702 }
703 NodeRef* NodeManager::audioOutputNode() const {
704 	Autolock _l(this);
705 	return m_audioOutputNode;
706 }
707 NodeRef* NodeManager::videoOutputNode() const {
708 	Autolock _l(this);
709 	return m_videoOutputNode;
710 }
711 
712 // fetch groups by index
713 // - you can write-lock the manager during sets of calls to these methods;
714 //   this ensures that the group set won't change.  The methods do lock
715 //   the group internally, so locking isn't explicitly required.
716 
717 uint32 NodeManager::countGroups() const {
718 	Autolock _l(this);
719 	D_METHOD((
720 		"NodeManager::countGroups()\n"));
721 
722 	return m_nodeGroupSet.size();
723 }
724 
725 NodeGroup* NodeManager::groupAt(
726 	uint32												index) const {
727 	Autolock _l(this);
728 	D_METHOD((
729 		"NodeManager::groupAt()\n"));
730 
731 	return (index < m_nodeGroupSet.size()) ?
732 		m_nodeGroupSet[index] :
733 		0;
734 }
735 
736 // look up a group by unique ID; returns B_BAD_VALUE if no
737 // matching group was found
738 
739 class match_group_by_id :
740 	public binary_function<const NodeGroup*, uint32, bool> {
741 public:
742 	bool operator()(const NodeGroup* group, uint32 id) const {
743 		return group->id() == id;
744 	}
745 };
746 
747 status_t NodeManager::findGroup(
748 	uint32												id,
749 	NodeGroup**										outGroup) const {
750 	Autolock _l(this);
751 	D_METHOD((
752 		"NodeManager::findGroup(id)\n"));
753 
754 	node_group_set::const_iterator it =
755 		find_if(
756 			m_nodeGroupSet.begin(),
757 			m_nodeGroupSet.end(),
758 			bind2nd(match_group_by_id(), id)
759 		);
760 
761 	if(it == m_nodeGroupSet.end()) {
762 		*outGroup = 0;
763 		return B_BAD_VALUE;
764 	}
765 
766 	*outGroup = *it;
767 	return B_OK;
768 }
769 
770 // look up a group by name; returns B_NAME_NOT_FOUND if
771 // no group matching the name was found.
772 
773 class match_group_by_name :
774 	public binary_function<const NodeGroup*, const char*, bool> {
775 public:
776 	bool operator()(const NodeGroup* group, const char* name) const {
777 		return !strcmp(group->name(), name);
778 	}
779 };
780 
781 status_t NodeManager::findGroup(
782 	const char*										name,
783 	NodeGroup**										outGroup) const {
784 	Autolock _l(this);
785 	D_METHOD((
786 		"NodeManager::findGroup(name)\n"));
787 
788 	node_group_set::const_iterator it =
789 		find_if(
790 			m_nodeGroupSet.begin(),
791 			m_nodeGroupSet.end(),
792 			bind2nd(match_group_by_name(), name)
793 		);
794 
795 	if(it == m_nodeGroupSet.end()) {
796 		*outGroup = 0;
797 		return B_BAD_VALUE;
798 	}
799 
800 	*outGroup = *it;
801 	return B_OK;
802 }
803 
804 // merge the given source group to the given destination;
805 // empties and releases the source group
806 
807 status_t NodeManager::mergeGroups(
808 	NodeGroup*										sourceGroup,
809 	NodeGroup*										destinationGroup) {
810 	Autolock _l(this);
811 	D_METHOD((
812 		"NodeManager::mergeGroups(name)\n"));
813 
814 	status_t err;
815 
816 	// [5feb00 c.lenz] already merged
817 	if(sourceGroup->id() == destinationGroup->id())
818 		return B_OK;
819 
820 	if(sourceGroup->isReleased() || destinationGroup->isReleased())
821 		return B_NOT_ALLOWED;
822 
823 	for(uint32 n = sourceGroup->countNodes(); n; --n) {
824 		NodeRef* node = sourceGroup->nodeAt(n-1);
825 		ASSERT(node);
826 		err = sourceGroup->removeNode(n-1);
827 		ASSERT(err == B_OK);
828 		err = destinationGroup->addNode(node);
829 		ASSERT(err == B_OK);
830 	}
831 
832 	// [7nov99 e.moon] delete the source group
833 	_removeGroup(sourceGroup);
834 	sourceGroup->release();
835 
836 	return B_OK;
837 }
838 
839 // [e.moon 28sep99]
840 // split group: given two nodes currently in the same group
841 // that are not connected (directly OR indirectly),
842 // this method removes outsideNode, and all nodes connected
843 // to outsideNode, from the common group.  These nodes are
844 // then added to a new group, returned in 'outGroup'.  The
845 // new group has " split" appended to the end of the original
846 // group's name.
847 //
848 // Returns B_NOT_ALLOWED if any of the above conditions aren't
849 // met (ie. the nodes are in different groups or an indirect
850 // route exists from one to the other), or B_OK if the group
851 // was split successfully.
852 
853 
854 class _changeNodeGroupFn :
855 	public	unary_function<NodeRef*, void> {
856 public:
857 	NodeGroup*										newGroup;
858 
859 	_changeNodeGroupFn(
860 		NodeGroup*									_newGroup) : newGroup(_newGroup) {
861 		ASSERT(newGroup);
862 	}
863 
864 	void operator()(
865 		NodeRef*										node) {
866 
867 		PRINT((
868 			"_changeNodeGroupFn(): '%s'\n", node->name()));
869 
870 		status_t err;
871 		NodeGroup* oldGroup = node->group();
872 		if(oldGroup) {
873 			err = oldGroup->removeNode(node);
874 			ASSERT(err == B_OK);
875 		}
876 
877 		err = newGroup->addNode(node);
878 		ASSERT(err == B_OK);
879 	}
880 };
881 
882 status_t NodeManager::splitGroup(
883 	NodeRef*											insideNode,
884 	NodeRef*											outsideNode,
885 	NodeGroup**										outGroup) {
886 
887 	ASSERT(insideNode);
888 	ASSERT(outsideNode);
889 
890 	Autolock _l(this);
891 
892 	// ensure that no route exists from insideNode to outsideNode
893 	if(findRoute(insideNode->id(), outsideNode->id())) {
894 		PRINT((
895 			"!!! NodeManager::splitGroup(): route exists from %ld to %ld\n",
896 			insideNode->id(), outsideNode->id()));
897 		return B_NOT_ALLOWED;
898 	}
899 
900 	// make sure the nodes share a common group
901 	NodeGroup* oldGroup = insideNode->group();
902 	if(!oldGroup) {
903 		PRINT((
904 			"!!! NodeManager::splitGroup(): invalid group\n",
905 			insideNode->id(), outsideNode->id()));
906 		return B_NOT_ALLOWED;
907 	}
908 	if(oldGroup != outsideNode->group()) {
909 		PRINT((
910 			"!!! NodeManager::splitGroup(): mismatched groups for %ld and %ld\n",
911 			insideNode->id(), outsideNode->id()));
912 		return B_NOT_ALLOWED;
913 	}
914 
915 	Autolock _l_old_group(oldGroup);
916 
917 	// create the new group
918 	BString nameBuffer = oldGroup->name();
919 	nameBuffer << " split";
920 
921 	NodeGroup* newGroup = createGroup(
922 		nameBuffer.String(),
923 		oldGroup->runMode());
924 	*outGroup = newGroup;
925 
926 	// move nodes connected to outsideNode from old to new group
927 	_changeNodeGroupFn fn(newGroup);
928 	fn(outsideNode);
929 
930 	_for_each_state st;
931 	_do_for_each_connected(
932 		this,
933 		outsideNode,
934 		oldGroup,
935 		true,
936 		fn,
937 		&st);
938 
939 	// [e.moon 1dec99] a single-node group takes that node's name
940 	if(newGroup->countNodes() == 1)
941 		newGroup->setName(newGroup->nodeAt(0)->name());
942 
943 	if(oldGroup->countNodes() == 1)
944 		oldGroup->setName(oldGroup->nodeAt(0)->name());
945 
946 	return B_OK;
947 }
948 
949 
950 // * INSTANTIATION & CONNECTION
951 //   Use these calls rather than the associated BMediaRoster()
952 //   methods to assure that the nodes and connections you set up
953 //   can be properly serialized & reconstituted.
954 
955 // basic BMediaRoster::InstantiateDormantNode() wrapper
956 
957 status_t NodeManager::instantiate(
958 	const dormant_node_info&			info,
959 	NodeRef**											outRef,
960 	bigtime_t											timeout,
961 	uint32												nodeFlags) {
962 
963 	Autolock _l(this);
964 	status_t err;
965 	D_METHOD((
966 		"NodeManager::instantiate()\n"));
967 
968 	// * instantiate
969 
970 	media_node node;
971 
972 	if(m_useAddOnHost) {
973 		err = AddOnHost::InstantiateDormantNode(
974 			info, &node, timeout);
975 
976 		if(err < B_OK) {
977 			node = media_node::null;
978 
979 			// attempt to relaunch
980 			BMessenger mess;
981 			err = AddOnHost::Launch(&mess);
982 			if(err < B_OK) {
983 				PRINT((
984 					"!!! NodeManager::instantiate(): giving up on AddOnHost\n"));
985 
986 				m_useAddOnHost = false;
987 			}
988 			else {
989 				err = AddOnHost::InstantiateDormantNode(
990 					info, &node, timeout);
991 			}
992 		}
993 	}
994 
995 	if(!m_useAddOnHost || node == media_node::null) {
996 		D_ROSTER((
997 			"# roster->InstantiateDormantNode()\n"));
998 		err = roster->InstantiateDormantNode(info, &node);
999 	}
1000 
1001 	if(err < B_OK) {
1002 		*outRef = 0;
1003 		return err;
1004 	}
1005 
1006 	if(node == media_node::null) {
1007 		// [e.moon 23oct99] +++++
1008 		// instantiating a soundcard input/output (emu10k or sonic_vibes)
1009 		// produces a node ID of -1 (R4.5.2 x86)
1010 		//
1011 		PRINT((
1012 			"! InstantiateDormantNode(): invalid media node\n"));
1013 
1014 		// bail out
1015 		*outRef = 0;
1016 		return B_BAD_INDEX;
1017 	}
1018 
1019 	// * create NodeRef
1020 	NodeRef* ref = new NodeRef(
1021 		node,
1022 		this,
1023 		nodeFlags, // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1024 		NodeRef::_INTERNAL);
1025 
1026 	ref->_setAddonHint(&info);
1027 	_addRef(ref);
1028 
1029 	// * return it
1030 	*outRef = ref;
1031 	return B_OK;
1032 }
1033 
1034 // SniffRef/Instantiate.../SetRefFor: a one-call interface
1035 // to create a node capable of playing a given media file.
1036 
1037 status_t NodeManager::instantiate(
1038 	const entry_ref&							file,
1039 	uint64												requireNodeKinds,
1040 	NodeRef**											outRef,
1041 	bigtime_t											timeout,
1042 	uint32												nodeFlags,
1043 	bigtime_t*										outDuration) {
1044 
1045 	D_METHOD((
1046 		"NodeManager::instantiate(ref)\n"));
1047 
1048 	// [no lock needed; calls the full form of instantiate()]
1049 
1050 	status_t err;
1051 
1052 	// * Find matching add-on
1053 	dormant_node_info info;
1054 
1055 	D_ROSTER((
1056 		"# roster->SniffRef()\n"));
1057 	err = roster->SniffRef(
1058 		file,
1059 		requireNodeKinds,
1060 		&info);
1061 	if(err < B_OK) {
1062 		*outRef = 0;
1063 		return err;
1064 	}
1065 
1066 	// * Instantiate
1067 	err = instantiate(info, outRef, timeout, nodeFlags);
1068 
1069 	if(err < B_OK)
1070 		return err;
1071 
1072 	ASSERT(*outRef);
1073 
1074 	// * Set file to play
1075 	bigtime_t dur;
1076 	D_ROSTER(("# roster->SetRefFor()\n"));
1077 	err = roster->SetRefFor(
1078 		(*outRef)->node(),
1079 		file,
1080 		false,
1081 		&dur);
1082 
1083 	if(err < B_OK) {
1084 		PRINT((
1085 			"* SetRefFor() failed: %s\n", strerror(err)));
1086 	}
1087 	else if(outDuration)
1088 		*outDuration = dur;
1089 
1090 	// * update info [e.moon 29sep99]
1091 	Autolock _l(*outRef);
1092 	(*outRef)->_setAddonHint(&info, &file);
1093 
1094 	return err;
1095 }
1096 
1097 // use this method to reference nodes internal to your
1098 // application.
1099 
1100 status_t NodeManager::reference(
1101 	BMediaNode*										node,
1102 	NodeRef**											outRef,
1103 	uint32												nodeFlags) {
1104 
1105 	Autolock _l(this);
1106 	D_METHOD((
1107 		"NodeManager::reference()\n"));
1108 
1109 	// should this node be marked _NO_RELEASE?
1110 	NodeRef* ref = new NodeRef(node->Node(), this, nodeFlags, 0);
1111 	_addRef(ref);
1112 
1113 	*outRef = ref;
1114 	return B_OK;
1115 }
1116 
1117 // the most flexible form of connect(): set the template
1118 // format as you would for BMediaRoster::Connect().
1119 
1120 status_t NodeManager::connect(
1121 	const media_output&						output,
1122 	const media_input&						input,
1123 	const media_format&						templateFormat,
1124 	Connection*										outConnection /*=0*/) {
1125 
1126 	Autolock _l(this);
1127 	status_t err;
1128 	D_METHOD((
1129 		"NodeManager::connect()\n"));
1130 
1131 	// * Find (& create if necessary) NodeRefs
1132 
1133 	NodeRef* outputRef;
1134 	if(getNodeRef(output.node.node, &outputRef) < B_OK)
1135 		outputRef = _addRefFor(output.node, 0);
1136 
1137 	NodeRef* inputRef;
1138 	if(getNodeRef(input.node.node, &inputRef) < B_OK)
1139 		inputRef = _addRefFor(input.node, 0);
1140 
1141 	// * Connect the nodes
1142 
1143 	media_output finalOutput;
1144 	media_input finalInput;
1145 	media_format finalFormat = templateFormat;
1146 
1147 	D_ROSTER(("# roster->Connect()\n"));
1148 	err = roster->Connect(
1149 		output.source,
1150 		input.destination,
1151 		&finalFormat,
1152 		&finalOutput,
1153 		&finalInput);
1154 
1155 	if(err < B_OK) {
1156 		if(outConnection)
1157 			*outConnection = Connection();
1158 		connectionFailed(output, input, templateFormat, err);
1159 		return err;
1160 	}
1161 
1162 	// * Create Connection instance; mark it INTERNAL
1163 	//   to automatically remove it upon shutdown.
1164 
1165 	D_METHOD((
1166 		"! creating connection:\n"
1167 		"  source id:    %ld\n"
1168 		"  source port:  %ld\n"
1169 		"  dest id:      %ld\n"
1170 		"  dest port:    %ld\n",
1171 		finalOutput.source.id, finalOutput.source.port,
1172 		finalInput.destination.id, finalInput.destination.port));
1173 
1174 	uint32 cflags = Connection::INTERNAL;
1175 	if(outputRef->m_info.node.kind & B_FILE_INTERFACE) {
1176 		// 3aug99:
1177 		// workaround for bug 19990802-12798:
1178 		//   connections involving a file-interface node aren't removed
1179 		cflags |= Connection::LOCKED;
1180 	}
1181 
1182 	Connection* con = new Connection(
1183 		m_nextConID++,
1184 		output.node,
1185 		finalOutput.source,
1186 		finalOutput.name,
1187 		input.node,
1188 		finalInput.destination,
1189 		finalInput.name,
1190 		finalFormat,
1191 		cflags);
1192 
1193 	con->setOutputHint(
1194 		output.name,
1195 		output.format);
1196 
1197 	con->setInputHint(
1198 		input.name,
1199 		input.format);
1200 
1201 	con->setRequestedFormat(
1202 		templateFormat);
1203 
1204 	_addConnection(con);
1205 
1206 	// [e.moon 10aug99]
1207 	// fetch updated latencies;
1208 	// [e.moon 28sep99]
1209 	// scan all nodes connected directly OR indirectly to the
1210 	// newly-connected nodes and update their latencies -- this includes
1211 	// recalculating the node's 'producer delay' if in B_RECORDING mode.
1212 
1213 	_updateLatenciesFrom(inputRef, true);
1214 
1215 	// copy connection
1216 	if(outConnection) {
1217 		*outConnection = *con;
1218 	}
1219 	return B_OK;
1220 }
1221 
1222 // format-guessing form of connect(): tries to find
1223 // a common format between output & input before connection;
1224 // returns B_MEDIA_BAD_FORMAT if no common format appears
1225 // possible.
1226 //
1227 // NOTE: the specifics of the input and output formats are ignored;
1228 //       this method only looks at the format type, and properly
1229 //       handles wildcards at that level (B_MEDIA_NO_TYPE).
1230 
1231 status_t NodeManager::connect(
1232 	const media_output&						output,
1233 	const media_input&						input,
1234 	Connection*										outConnection /*=0*/) {
1235 
1236 	D_METHOD((
1237 		"NodeManager::connect(guess)\n"));
1238 
1239 	// [no lock needed; calls the full form of connect()]
1240 
1241 	// defer to the pickier endpoint
1242 	media_format f;
1243 
1244 	if(output.format.type > B_MEDIA_UNKNOWN_TYPE) {
1245 		f = output.format;
1246 		if ((input.format.type > B_MEDIA_UNKNOWN_TYPE) &&
1247 			(f.type != input.format.type)) {
1248 			connectionFailed(output, input, f, B_MEDIA_BAD_FORMAT);
1249 			return B_MEDIA_BAD_FORMAT;
1250 		}
1251 	}
1252 	else if(input.format.type > B_MEDIA_UNKNOWN_TYPE) {
1253 		f = input.format;
1254 		// output node doesn't care
1255 	}
1256 	else {
1257 		// about as non-picky as two nodes can possibly be
1258 		f.type = B_MEDIA_UNKNOWN_TYPE;
1259 	}
1260 
1261 	// +++++ ? revert to wildcard ?
1262 
1263 	// let the nodes try to work out a common format from here
1264 	return connect(
1265 		output,
1266 		input,
1267 		f,
1268 		outConnection);
1269 }
1270 
1271 // disconnects the connection represented by the provided
1272 // Connection object.  if successful, returns B_OK.
1273 
1274 status_t NodeManager::disconnect(
1275 	const Connection&								connection) {
1276 
1277 	Autolock _l(this);
1278 	status_t err;
1279 	D_METHOD((
1280 		"NodeManager::disconnect()\n"));
1281 
1282 	// don't bother trying to disconnect an invalid connection
1283 	if(!connection.isValid())
1284 		return B_NOT_ALLOWED;
1285 
1286 	// make sure connection can be released
1287 	if(connection.flags() & Connection::LOCKED) {
1288 		PRINT((
1289 			"NodeManager::disconnect(): connection locked:\n"
1290 			"  %ld:%s -> %ld:%s\n",
1291 			connection.sourceNode(),
1292 			connection.outputName(),
1293 			connection.destinationNode(),
1294 			connection.inputName()));
1295 		return B_NOT_ALLOWED;
1296 	}
1297 
1298 	D_METHOD((
1299 		"! breaking connection:\n"
1300 		"  source node:  %ld\n"
1301 		"  source id:    %ld\n"
1302 		"  source port:  %ld\n"
1303 		"  dest node:    %ld\n"
1304 		"  dest id:      %ld\n"
1305 		"  dest port:    %ld\n",
1306 		connection.sourceNode(),
1307 		connection.source().id, connection.source().port,
1308 		connection.destinationNode(),
1309 		connection.destination().id, connection.destination().port));
1310 
1311 	// do it
1312 	D_ROSTER(("# roster->Disconnect()\n"));
1313 	err = roster->Disconnect(
1314 		connection.sourceNode(),
1315 		connection.source(),
1316 		connection.destinationNode(),
1317 		connection.destination());
1318 
1319 	// mark disconnected
1320 	if(err == B_OK) {
1321 		con_map::iterator it = m_conSourceMap.lower_bound(connection.sourceNode());
1322 		con_map::iterator itEnd = m_conSourceMap.upper_bound(connection.sourceNode());
1323 		for(; it != itEnd; ++it)
1324 			if((*it).second->id() == connection.id()) {
1325 				(*it).second->m_disconnected = true;
1326 				break;
1327 			}
1328 		ASSERT(it != itEnd);
1329 
1330 		// [e.moon 28sep99]
1331 		// fetch updated latencies;
1332 		// scan all nodes connected directly OR indirectly to the
1333 		// newly-connected nodes and update their latencies -- this includes
1334 		// recalculating the node's 'producer delay' if in B_RECORDING mode.
1335 
1336 		NodeRef* ref;
1337 		if(getNodeRef(connection.sourceNode(), &ref) == B_OK)
1338 			_updateLatenciesFrom(ref, true);
1339 		if(getNodeRef(connection.destinationNode(), &ref) == B_OK)
1340 			_updateLatenciesFrom(ref, true);
1341 
1342 	} else {
1343 		// +++++ if this failed, somebody somewhere is mighty confused
1344 		PRINT((
1345 			"NodeManager::disconnect(): Disconnect() failed:\n  %s\n",
1346 			strerror(err)));
1347 	}
1348 
1349 	return err;
1350 }
1351 
1352 // * GROUP CREATION
1353 
1354 NodeGroup* NodeManager::createGroup(
1355 	const char*										name,
1356 	BMediaNode::run_mode					runMode) {
1357 
1358 	Autolock _l(this);
1359 	D_METHOD((
1360 		"NodeManager::createGroup()\n"));
1361 
1362 	NodeGroup* g = new NodeGroup(name, this, runMode);
1363 	_addGroup(g);
1364 
1365 	return g;
1366 }
1367 
1368 // -------------------------------------------------------- //
1369 // *** node/connection iteration
1370 // *** MUST BE LOCKED for any of these calls
1371 // -------------------------------------------------------- //
1372 
1373 // usage:
1374 //   For the first call, pass 'cookie' a pointer to a void* set to 0.
1375 //   Returns B_BAD_INDEX when the set of nodes has been exhausted (and
1376 //   re-zeroes the cookie, cleaning up any unused memory.)
1377 
1378 status_t NodeManager::getNextRef(
1379 	NodeRef**											ref,
1380 	void**												cookie) {
1381 	ASSERT(IsLocked());
1382 	ASSERT(cookie);
1383 
1384 	if(!*cookie)
1385 		*cookie = new node_ref_map::iterator(m_nodeRefMap.begin());
1386 
1387 	node_ref_map::iterator* pit = (node_ref_map::iterator*)*cookie;
1388 
1389 	// at end of set?
1390 	if(*pit == m_nodeRefMap.end()) {
1391 		delete pit;
1392 		*cookie = 0;
1393 		return B_BAD_INDEX;
1394 	}
1395 
1396 	// return next entry
1397 	*ref = (*(*pit)).second;
1398 	++(*pit);
1399 	return B_OK;
1400 }
1401 
1402 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
1403 void NodeManager::disposeRefCookie(
1404 	void**												cookie) {
1405 
1406 	if(!cookie)
1407 		return;
1408 
1409 	node_ref_map::iterator* it =
1410 		reinterpret_cast<node_ref_map::iterator*>(*cookie);
1411 	ASSERT(it);
1412 	if(it)
1413 		delete it;
1414 }
1415 
1416 status_t NodeManager::getNextConnection(
1417 	Connection*										connection,
1418 	void**												cookie) {
1419 	ASSERT(IsLocked());
1420 	ASSERT(cookie);
1421 
1422 	if(!*cookie)
1423 		*cookie = new con_map::iterator(m_conSourceMap.begin());
1424 
1425 	con_map::iterator* pit = (con_map::iterator*)*cookie;
1426 
1427 	// at end of set?
1428 	if(*pit == m_conSourceMap.end()) {
1429 		delete pit;
1430 		*cookie = 0;
1431 		return B_BAD_INDEX;
1432 	}
1433 
1434 	// return next entry (ewww)
1435 	*connection = *((*(*pit)).second);
1436 	++(*pit);
1437 	return B_OK;
1438 }
1439 
1440 // +++++ reworked 13sep99: dtors wouldn't have been called with 'delete *cookie'! +++++
1441 void NodeManager::disposeConnectionCookie(
1442 	void**												cookie) {
1443 
1444 	if(!cookie)
1445 		return;
1446 
1447 	con_map::iterator* it =
1448 		reinterpret_cast<con_map::iterator*>(*cookie);
1449 	ASSERT(it);
1450 	if(it)
1451 		delete it;
1452 }
1453 
1454 
1455 // -------------------------------------------------------- //
1456 // *** BHandler impl
1457 // -------------------------------------------------------- //
1458 
1459 // +++++ support all Media Roster messages! +++++
1460 
1461 // [e.moon 7nov99] implemented observer pattern for NodeGroup
1462 void NodeManager::MessageReceived(BMessage* message) {
1463 
1464 	D_MESSAGE((
1465 		"NodeManager::MessageReceived(): %c%c%c%c\n",
1466 		 message->what >> 24,
1467 		(message->what >> 16)	& 0xff,
1468 		(message->what >> 8)	& 0xff,
1469 		(message->what) 			& 0xff));
1470 
1471 	switch(message->what) {
1472 
1473 		// *** Media Roster messages ***
1474 
1475 		case B_MEDIA_NODE_CREATED:
1476 			if(_handleNodesCreated(message) == B_OK)
1477 				notify(message);
1478 			break;
1479 
1480 		case B_MEDIA_NODE_DELETED:
1481 			_handleNodesDeleted(message);
1482 			notify(message);
1483 			break;
1484 
1485 		case B_MEDIA_CONNECTION_MADE:
1486 			_handleConnectionMade(message);
1487 			notify(message);
1488 			break;
1489 
1490 		case B_MEDIA_CONNECTION_BROKEN:
1491 			_handleConnectionBroken(message); // augments message!
1492 			notify(message);
1493 			break;
1494 
1495 		case B_MEDIA_FORMAT_CHANGED:
1496 			_handleFormatChanged(message);
1497 			notify(message);
1498 			break;
1499 
1500 		default:
1501 			_inherited::MessageReceived(message);
1502 			break;
1503 	}
1504 }
1505 
1506 // -------------------------------------------------------- //
1507 // *** IObservable hooks
1508 // -------------------------------------------------------- //
1509 
1510 void NodeManager::observerAdded(
1511 	const BMessenger&				observer) {
1512 
1513 	BMessage m(M_OBSERVER_ADDED);
1514 	m.AddMessenger("target", BMessenger(this));
1515 	observer.SendMessage(&m);
1516 }
1517 
1518 
1519 void NodeManager::observerRemoved(
1520 	const BMessenger&				observer) {
1521 
1522 	BMessage m(M_OBSERVER_REMOVED);
1523 	m.AddMessenger("target", BMessenger(this));
1524 	observer.SendMessage(&m);
1525 }
1526 
1527 void NodeManager::notifyRelease() {
1528 
1529 	BMessage m(M_RELEASED);
1530 	m.AddMessenger("target", BMessenger(this));
1531 	notify(&m);
1532 }
1533 
1534 void NodeManager::releaseComplete() {
1535 	// tear down media roster connection
1536 	D_ROSTER(("# roster->StopWatching()\n"));
1537 	status_t err = roster->StopWatching(
1538 		BMessenger(this));
1539 	if(err < B_OK) {
1540 		PRINT((
1541 			"* roster->StopWatching() failed: %s\n", strerror(err)));
1542 	}
1543 }
1544 
1545 
1546 // -------------------------------------------------------- //
1547 // *** ILockable impl.
1548 // -------------------------------------------------------- //
1549 
1550 bool NodeManager::lock(
1551 	lock_t												type,
1552 	bigtime_t											timeout) {
1553 
1554 	D_LOCK(("*** NodeManager::lock(): %ld\n", find_thread(0)));
1555 
1556 	status_t err = LockWithTimeout(timeout);
1557 
1558 
1559 	D_LOCK(("*** NodeManager::lock() ACQUIRED: %ld\n", find_thread(0)));
1560 
1561 	return err == B_OK;
1562 }
1563 
1564 bool NodeManager::unlock(
1565 	lock_t												type) {
1566 
1567 	D_LOCK(("*** NodeManager::unlock(): %ld\n", find_thread(0)));
1568 
1569 	Unlock();
1570 
1571 	D_LOCK(("*** NodeManager::unlock() RELEASED: %ld\n", find_thread(0)));
1572 
1573 	return true;
1574 }
1575 
1576 bool NodeManager::isLocked(
1577 	lock_t												type) const {
1578 
1579 	return IsLocked();
1580 }
1581 
1582 // -------------------------------------------------------- //
1583 // *** internal operations (LOCK REQUIRED)
1584 // -------------------------------------------------------- //
1585 
1586 void NodeManager::_initCommonNodes() {
1587 
1588 	ASSERT(IsLocked());
1589 	status_t err;
1590 	media_node node;
1591 
1592 	D_METHOD((
1593 		"NodeManager::_initCommonNodes()\n"));
1594 
1595 	uint32 disableTransport =
1596 		(NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL);
1597 
1598 	// video input
1599 	D_ROSTER(("# roster->GetVideoInput()\n"));
1600 	err = roster->GetVideoInput(&node);
1601 	if(err == B_OK)
1602 		m_videoInputNode = _addRefFor(
1603 			node,
1604 			_userFlagsForKind(node.kind),
1605 			_implFlagsForKind(node.kind));
1606 
1607 	// video output
1608 	D_ROSTER(("# roster->GetVideoOutput()\n"));
1609 	err = roster->GetVideoOutput(&node);
1610 	if(err == B_OK) {
1611 		if(m_videoInputNode && node.node == m_videoInputNode->id()) {
1612 			// input and output nodes identical
1613 			// [e.moon 20dec99]
1614 			m_videoOutputNode = m_videoInputNode;
1615 		}
1616 		else {
1617 			m_videoOutputNode = _addRefFor(
1618 				node,
1619 				_userFlagsForKind(node.kind) & ~NodeRef::NO_START_STOP,
1620 				_implFlagsForKind(node.kind));
1621 		}
1622 	}
1623 
1624 	// audio mixer
1625 	D_ROSTER(("# roster->GetAudioMixer()\n"));
1626 	err = roster->GetAudioMixer(&node);
1627 	if(err == B_OK)
1628 		m_audioMixerNode = _addRefFor(
1629 			node,
1630 			_userFlagsForKind(node.kind) | disableTransport,
1631 			_implFlagsForKind(node.kind));
1632 
1633 	// audio input
1634 	D_ROSTER(("# roster->GetAudioInput()\n"));
1635 	err = roster->GetAudioInput(&node);
1636 	if(err == B_OK)
1637 		m_audioInputNode = _addRefFor(
1638 			node,
1639 			_userFlagsForKind(node.kind),
1640 			_implFlagsForKind(node.kind));
1641 
1642 	// audio output
1643 	D_ROSTER(("# roster->GetAudioOutput()\n"));
1644 	err = roster->GetAudioOutput(&node);
1645 	if(err == B_OK) {
1646 		if(m_audioInputNode && node.node == m_audioInputNode->id()) {
1647 			// input and output nodes identical
1648 			// [e.moon 20dec99]
1649 			m_audioOutputNode = m_audioInputNode;
1650 
1651 			// disable transport controls (the default audio output must always
1652 			// be running, and can't be seeked.)
1653 
1654 			m_audioOutputNode->setFlags(
1655 				m_audioOutputNode->flags() | disableTransport);
1656 		}
1657 		else {
1658 			m_audioOutputNode = _addRefFor(
1659 				node,
1660 				_userFlagsForKind(node.kind) | disableTransport,
1661 				_implFlagsForKind(node.kind));
1662 		}
1663 	}
1664 }
1665 
1666 void NodeManager::_addRef(
1667 	NodeRef*											ref) {
1668 
1669 	ASSERT(ref);
1670 	ASSERT(IsLocked());
1671 
1672 	D_METHOD((
1673 		"NodeManager::_addRef()\n"));
1674 
1675 	// precondition: no NodeRef yet exists for this node
1676 	// +++++
1677 	// [e.moon 21oct99]
1678 	// <markjan@xs4all.nl> sez this fails on startup w/ MediaKit 10.5
1679 	ASSERT(
1680 		m_nodeRefMap.find(ref->id()) == m_nodeRefMap.end());
1681 
1682 	// add it
1683 	// [e.moon 13oct99] PPC-friendly
1684 	m_nodeRefMap.insert(node_ref_map::value_type(ref->id(), ref));
1685 
1686 	// [e.moon 8nov99] call hook
1687 	nodeCreated(ref);
1688 }
1689 
1690 void NodeManager::_removeRef(
1691 	media_node_id									id) {
1692 	ASSERT(IsLocked());
1693 
1694 	D_METHOD((
1695 		"NodeManager::_removeRef()\n"));
1696 
1697 	node_ref_map::iterator it = m_nodeRefMap.find(id);
1698 
1699 	// precondition: a NodeRef w/ matching ID is in the map
1700 	ASSERT(it != m_nodeRefMap.end());
1701 
1702 	// [e.moon 8nov99] call hook
1703 	nodeDeleted((*it).second);
1704 
1705 	// remove it
1706 	m_nodeRefMap.erase(it);
1707 }
1708 
1709 // create, add, return a NodeRef for the given external node;
1710 // must not already exist
1711 NodeRef* NodeManager::_addRefFor(
1712 	const media_node&							node,
1713 	uint32												nodeFlags,
1714 	uint32												nodeImplFlags) {
1715 
1716 	ASSERT(IsLocked());
1717 
1718 	D_METHOD((
1719 		"NodeManager::_addRefFor()\n"));
1720 
1721 	// precondition: no NodeRef yet exists for this node
1722 	ASSERT(
1723 		m_nodeRefMap.find(node.node) == m_nodeRefMap.end());
1724 
1725 //	// precondition: the node actually exists
1726 //	live_node_info info;
1727 //	D_ROSTER(("# roster->GetLiveNodeInfo()\n"));
1728 //	ASSERT(roster->GetLiveNodeInfo(node, &info) == B_OK);
1729 
1730 	// * create & add ref
1731 	NodeRef* ref = new NodeRef(node, this, nodeFlags, nodeImplFlags);
1732 	_addRef(ref);
1733 
1734 	return ref;
1735 }
1736 
1737 void NodeManager::_addConnection(
1738 	Connection*										connection) {
1739 
1740 	ASSERT(connection);
1741 	ASSERT(IsLocked());
1742 
1743 	D_METHOD((
1744 		"NodeManager::_addConnection()\n"));
1745 
1746 	// precondition: not already entered in either source or dest map
1747 	// +++++ a more rigorous test would be a very good thing
1748 #ifdef DEBUG
1749 	for(con_map::iterator it = m_conSourceMap.lower_bound(connection->sourceNode());
1750 		it != m_conSourceMap.upper_bound(connection->sourceNode()); ++it) {
1751 		ASSERT((*it).second->id() != connection->id());
1752 	}
1753 	for(con_map::iterator it = m_conDestinationMap.lower_bound(connection->destinationNode());
1754 		it != m_conDestinationMap.upper_bound(connection->destinationNode()); ++it) {
1755 		ASSERT((*it).second->id() != connection->id());
1756 	}
1757 #endif
1758 
1759 	// add to both maps
1760 	// [e.moon 13oct99] PPC-friendly
1761 	m_conSourceMap.insert(
1762 		con_map::value_type(
1763 			connection->sourceNode(),
1764 			connection));
1765 	m_conDestinationMap.insert(
1766 		con_map::value_type(
1767 			connection->destinationNode(),
1768 			connection));
1769 
1770 	// [e.moon 8nov99] call hook
1771 	connectionMade(connection);
1772 }
1773 
1774 void NodeManager::_removeConnection(
1775 	const Connection&							connection) {
1776 
1777 	ASSERT(IsLocked());
1778 	con_map::iterator itSource, itDestination;
1779 
1780 	D_METHOD((
1781 		"NodeManager::_removeConnection()\n"));
1782 
1783 	// [e.moon 8nov99] call hook
1784 	connectionBroken(&connection);
1785 
1786 	// precondition: one entry in both source & dest maps
1787 	// +++++ a more rigorous test would be a very good thing
1788 
1789 	for(
1790 		itSource = m_conSourceMap.lower_bound(connection.sourceNode());
1791 		itSource != m_conSourceMap.upper_bound(connection.sourceNode());
1792 		++itSource)
1793 		if((*itSource).second->id() == connection.id())
1794 			break;
1795 
1796 	ASSERT(itSource != m_conSourceMap.end());
1797 
1798 	for(
1799 		itDestination = m_conDestinationMap.lower_bound(connection.destinationNode());
1800 		itDestination != m_conDestinationMap.upper_bound(connection.destinationNode());
1801 		++itDestination)
1802 		if((*itDestination).second->id() == connection.id())
1803 			break;
1804 
1805 	ASSERT(itDestination != m_conDestinationMap.end());
1806 
1807 	// delete & remove from both maps
1808 	delete (*itSource).second;
1809 	m_conSourceMap.erase(itSource);
1810 	m_conDestinationMap.erase(itDestination);
1811 }
1812 
1813 void NodeManager::_addGroup(
1814 	NodeGroup*										group) {
1815 
1816 	ASSERT(group);
1817 	ASSERT(IsLocked());
1818 
1819 	D_METHOD((
1820 		"NodeManager::_addGroup()\n"));
1821 
1822 	// precondition: group not already in set
1823 	ASSERT(
1824 		find(
1825 			m_nodeGroupSet.begin(),
1826 			m_nodeGroupSet.end(),
1827 			group) == m_nodeGroupSet.end());
1828 
1829 	// add
1830 	m_nodeGroupSet.push_back(group);
1831 
1832 //	// [e.moon 7nov99] observe
1833 //	add_observer(this, group);
1834 }
1835 
1836 void NodeManager::_removeGroup(
1837 	NodeGroup*										group) {
1838 
1839 	ASSERT(group);
1840 	ASSERT(IsLocked());
1841 
1842 	D_METHOD((
1843 		"NodeManager::_removeGroup()\n"));
1844 
1845 	node_group_set::iterator it = find(
1846 		m_nodeGroupSet.begin(),
1847 		m_nodeGroupSet.end(),
1848 		group);
1849 
1850 	// precondition: group in set
1851 	if(it == m_nodeGroupSet.end()) {
1852 		PRINT((
1853 			"* NodeManager::_removeGroup(%ld): group not in set.\n",
1854 			group->id()));
1855 		return;
1856 	}
1857 
1858 	// remove it
1859 	m_nodeGroupSet.erase(it);
1860 }
1861 
1862 // -------------------------------------------------------- //
1863 // *** Message Handlers ***
1864 // -------------------------------------------------------- //
1865 
1866 
1867 // now returns B_OK iff the message should be relayed to observers
1868 // [e.moon 11oct99]
1869 
1870 inline status_t NodeManager::_handleNodesCreated(
1871 	BMessage*											message) {
1872 	ASSERT(IsLocked());
1873 
1874 	status_t err = B_OK;
1875 
1876 	// fetch number of new nodes
1877 	type_code type;
1878 	int32 count;
1879 	err = message->GetInfo("media_node_id", &type, &count);
1880 	if(err < B_OK) {
1881 		PRINT((
1882 			"* NodeManager::_handleNodesCreated(): GetInfo() failed:\n"
1883 			"  %s\n",
1884 			strerror(err)));
1885 		return err;
1886 	}
1887 	if(!count) {
1888 		PRINT((
1889 			"* NodeManager::_handleNodesCreated(): no node IDs in message.\n"));
1890 		return err;
1891 	}
1892 
1893 	D_METHOD((
1894 		"NodeManager::_handleNodesCreated(): %d nodes\n",
1895 		count));
1896 
1897 	// * Create NodeRef instances for the listed nodes.
1898 	//   If this is the first message received from the Media Roster,
1899 	//   no connection info will be received for these nodes; store them
1900 	//   for now (indexed by service-thread port) and figure the connections
1901 	//   afterwards.
1902 	//   These nodes are mapped by port ID because that's the only criterion
1903 	//   available for matching a media_source to a node.
1904 
1905 	typedef map<port_id, NodeRef*> port_ref_map;
1906 	port_ref_map* initialNodes = m_existingNodesInit ? 0 : new port_ref_map;
1907 
1908 	bool refsCreated = false;
1909 
1910 	for(int32 n = 0; n < count; ++n) {
1911 		// fetch ID of next node
1912 		int32 id;
1913 		err = message->FindInt32("media_node_id", n, &id);
1914 		if(err < B_OK) {
1915 			PRINT((
1916 				"* NodeManager::_handleNodesCreated(): FindInt32() failed:\n"
1917 				"  %s", strerror(err)));
1918 			continue;
1919 		}
1920 
1921 		// look up the node
1922 		media_node node;
1923 		err = roster->GetNodeFor(id, &node);
1924 		if(err < B_OK) {
1925 			PRINT((
1926 				"* NodeManager::_handleNodesCreated(): roster->GetNodeFor(%ld) failed:\n"
1927 				"  %s\n",
1928 				id, strerror(err)));
1929 			continue;
1930 		}
1931 
1932 		// look for an existing NodeRef; if not found, create one:
1933 		NodeRef* ref = 0;
1934 		if(getNodeRef(node.node, &ref) < B_OK) {
1935 			// create one
1936 			ref = _addRefFor(
1937 				node,
1938 				_userFlagsForKind(node.kind), // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1939 				_implFlagsForKind(node.kind) | NodeRef::_CREATE_NOTIFIED);
1940 
1941 			refsCreated = true;
1942 
1943 //			// [e.moon 7nov99] call hook
1944 //			nodeCreated(ref);
1945 
1946 		} else {
1947 //			PRINT((
1948 //				"* NodeManager::_handleNodesCreated():\n"
1949 //				"  found existing ref for '%s' (%ld)\n",
1950 //				ref->name(), id));
1951 
1952 
1953 			// set _CREATE_NOTIFIED to prevent notification from being passed on
1954 			// twice [e.moon 11oct99]
1955 			if(!(ref->m_implFlags & NodeRef::_CREATE_NOTIFIED)) {
1956 				ref->m_implFlags |= NodeRef::_CREATE_NOTIFIED;
1957 				refsCreated = true;
1958 			}
1959 
1960 			// release the (duplicate) media_node reference
1961 			err = roster->ReleaseNode(node);
1962 			if(err < B_OK) {
1963 				PRINT((
1964 					"* NodeManager::_handleNodesCreated(): roster->ReleaseNode(%ld) failed:\n"
1965 					"  %s\n",
1966 					id, strerror(err)));
1967 			}
1968 		}
1969 
1970 		// add to the 'initial nodes' set if necessary
1971 		// [e.moon 13oct99] PPC-friendly
1972 		if(initialNodes)
1973 			initialNodes->insert(
1974 				port_ref_map::value_type(
1975 					node.port, ref));
1976 	}
1977 
1978 	if(initialNodes) {
1979 		// populate current connections from each node in the set
1980 //		PRINT((
1981 //			"* NodeManager::_handleNodesCreated(): POPULATING CONNECTIONS (%ld)\n",
1982 //			initialNodes->size()));
1983 
1984 		for(port_ref_map::const_iterator itDest = initialNodes->begin();
1985 			itDest != initialNodes->end(); ++itDest) {
1986 
1987 			// walk each connected input for this node; find corresponding
1988 			// output & fill in a new Connection instance.
1989 
1990 			NodeRef* destRef = (*itDest).second;
1991 			ASSERT(destRef);
1992 			if(!(destRef->kind() & B_BUFFER_CONSUMER))
1993 				// no inputs
1994 				continue;
1995 
1996 			vector<media_input> inputs;
1997 			err = destRef->getConnectedInputs(inputs);
1998 
1999 			// +++++ FAILED ON STARTUP [e.moon 28sep99]; haven't reproduced yet
2000 			//       [21oct99] failed again
2001 			//ASSERT(err == B_OK);
2002 			if(err < B_OK) {
2003 				PRINT((
2004 					"!!! NodeManager::_handleNodesCreated():\n"
2005 					"    NodeRef('%s')::getConnectedInputs() failed:\n"
2006 					"    %s\n",
2007 					destRef->name(), strerror(err)));
2008 
2009 				continue;
2010 			}
2011 
2012 
2013 //			PRINT((" - %s: %ld inputs\n", destRef->name(), inputs.size()));
2014 
2015 			for(vector<media_input>::const_iterator itInput = inputs.begin();
2016 				itInput != inputs.end(); ++itInput) {
2017 
2018 				// look for a matching source node by port ID:
2019 				const media_input& input = *itInput;
2020 				port_ref_map::const_iterator itSource = initialNodes->find(
2021 					input.source.port);
2022 
2023 				if(itSource == initialNodes->end()) {
2024 					// source not found!
2025 					PRINT((
2026 						"* NodeManager::_handleNodesCreated():\n"
2027 						"  Building initial Connection set: couldn't find source node\n"
2028 						"  connected to input '%s' of '%s' (source port %d).\n",
2029 						input.name, destRef->name(), input.source.port));
2030 					continue;
2031 				}
2032 
2033 				// found it; fetch matching output
2034 				NodeRef* sourceRef = (*itSource).second;
2035 				ASSERT(sourceRef);
2036 				media_output output;
2037 				err = sourceRef->findOutput(input.source, &output);
2038 				if(err < B_OK) {
2039 					PRINT((
2040 						"* NodeManager::_handleNodesCreated():\n"
2041 						"  Building initial Connection set: couldn't find output\n"
2042 						"  in node '%s' connected to input '%s' of '%s'.\n",
2043 						sourceRef->name(),
2044 						input.name, destRef->name()));
2045 					continue;
2046 				}
2047 
2048 				// sanity check
2049 //				ASSERT(input.source == output.source);
2050 //				ASSERT(input.destination == output.destination);
2051 				// diagnostics [e.moon 11jan00]
2052 				if(input.source != output.source ||
2053 					input.destination != output.destination) {
2054 					PRINT((
2055 						"!!! NodeManager::_handleNodesCreated():\n"
2056 						"    input/output mismatch for connection\n"
2057 						"    '%s' (%s) -> '%s' (%s)\n"
2058 						"    input.source:        port %ld, ID %ld\n"
2059 						"    output.source:       port %ld, ID %ld\n"
2060 						"    input.destination:   port %ld, ID %ld\n"
2061 						"    output.destination:  port %ld, ID %ld\n\n",
2062 						sourceRef->name(), output.name,
2063 						destRef->name(), input.name,
2064 						input.source.port, input.source.id,
2065 						output.source.port, output.source.id,
2066 						input.destination.port, input.destination.id,
2067 						output.destination.port, output.destination.id));
2068 					continue;
2069 				}
2070 
2071 				// instantiate & add connection
2072 
2073 				uint32 flags = 0;
2074 
2075 				// 22sep99: lock audio-mixer connection
2076 				if(
2077 					sourceRef == m_audioMixerNode &&
2078 					destRef == m_audioOutputNode)
2079 					flags |= Connection::LOCKED;
2080 
2081 				Connection* con = new Connection(
2082 					m_nextConID++,
2083 					output.node,
2084 					output.source,
2085 					output.name,
2086 					input.node,
2087 					input.destination,
2088 					input.name,
2089 					input.format,
2090 					flags);
2091 
2092 				_addConnection(con);
2093 
2094 //				// [e.moon 7nov99] call hook
2095 //				connectionMade(con);
2096 
2097 //				PRINT((
2098 //					"* NodeManager::_handleNodesCreated(): Found initial connection:\n"
2099 //					"  %s:%s -> %s:%s\n",
2100 //					sourceRef->name(), con->outputName(),
2101 //					destRef->name(), con->inputName()));
2102 
2103 			} // for(vector<media_input> ...
2104 
2105 		} // for(port_ref_map ...
2106 
2107 		// mark the ordeal as over & done with
2108 		m_existingNodesInit = true;
2109 		// clean up
2110 		delete initialNodes;
2111 	}
2112 
2113 	// don't relay message if no new create notifications were received [e.moon 11oct99]
2114 	return refsCreated ? B_OK : B_ERROR;
2115 }
2116 
2117 inline void NodeManager::_handleNodesDeleted(
2118 	BMessage*											message) {
2119 	ASSERT(IsLocked());
2120 
2121 	D_METHOD((
2122 		"NodeManager::_handleNodesDeleted()\n"));
2123 
2124 	// walk the list of deleted nodes, removing & cleaning up refs
2125 	// (and any straggler connections)
2126 
2127 	type_code type;
2128 	int32 count;
2129 	status_t err = message->GetInfo("media_node_id", &type, &count);
2130 	if(err < B_OK) {
2131 		PRINT((
2132 			"* NodeManager::_handleNodesDeleted(): GetInfo() failed:\n"
2133 			"  %s\n",
2134 			strerror(err)));
2135 		return;
2136 	}
2137 	if(!count)
2138 		return;
2139 
2140 	for(int32 n = 0; n < count; n++) {
2141 
2142 		int32 id;
2143 		err = message->FindInt32("media_node_id", n, &id);
2144 		if(err < B_OK) {
2145 			PRINT((
2146 				"* NodeManager::_handleNodesDeleted(): FindInt32() failed\n"
2147 				"  %s\n",
2148 				strerror(err)));
2149 			continue;
2150 		}
2151 
2152 		// fetch ref
2153 		NodeRef* ref;
2154 		err = getNodeRef(id, &ref);
2155 		if(err < B_OK) {
2156 			PRINT((
2157 				"* NodeManager::_handleNodesDeleted(): getNodeRef(%ld) failed\n"
2158 				"  %s\n",
2159 				id, strerror(err)));
2160 			continue;
2161 		}
2162 
2163 		// find & remove any 'stuck' connections; notify any observers
2164 		// that the connections have been removed
2165 		vector<Connection> stuckConnections;
2166 		ref->getInputConnections(stuckConnections);
2167 		ref->getOutputConnections(stuckConnections);
2168 
2169 		BMessage message(B_MEDIA_CONNECTION_BROKEN);
2170 
2171 		for(uint32 n = 0; n < stuckConnections.size(); ++n) {
2172 			Connection& c = stuckConnections[n];
2173 
2174 			// generate a complete B_MEDIA_CONNECTION_BROKEN message
2175 			// +++++ the message format may be extended in the future -- ick
2176 
2177 			message.AddData("source", B_RAW_TYPE, &c.source(), sizeof(media_source));
2178 			message.AddData("destination", B_RAW_TYPE, &c.destination(), sizeof(media_destination));
2179 			message.AddInt32(_connectionField, c.id());
2180 			message.AddInt32(_sourceNodeField, c.sourceNode());
2181 			message.AddInt32(_destNodeField, c.destinationNode());
2182 
2183 			_removeConnection(c);
2184 		}
2185 
2186 		// +++++ don't notify if no stuck connections were found
2187 		notify(&message);
2188 
2189 		// ungroup if necessary
2190 		if(ref->m_group) {
2191 			ASSERT(!ref->isReleased());
2192 			ref->m_group->removeNode(ref);
2193 		}
2194 
2195 		// [e.moon 23oct99] mark the node released!
2196 		ref->m_nodeReleased = true;
2197 
2198 //		// [e.moon 7nov99] call hook
2199 //		nodeDeleted(ref);
2200 
2201 		// release it
2202 		ref->release();
2203 
2204 	} // for(int32 n ...
2205 }
2206 
2207 inline void NodeManager::_handleConnectionMade(
2208 	BMessage*											message) {
2209 	ASSERT(IsLocked());
2210 	D_METHOD((
2211 		"NodeManager::_handleConnectionMade()\n"));
2212 	status_t err;
2213 
2214 	for(int32 n = 0;;++n) {
2215 		media_input input;
2216 		media_output output;
2217 		const void* data;
2218 		ssize_t dataSize;
2219 
2220 		// fetch output
2221 		err = message->FindData("output", B_RAW_TYPE, n, &data, &dataSize);
2222 		if(err < B_OK) {
2223 			if(!n) {
2224 				PRINT((
2225 					"* NodeManager::_handleConnectionMade(): no entries in message.\n"));
2226 			}
2227 			break;
2228 		}
2229 		if(dataSize < ssize_t(sizeof(media_output))) {
2230 			PRINT((
2231 				"* NodeManager::_handleConnectionMade(): not enough data for output.\n"));
2232 			break;
2233 		}
2234 		output = *(media_output*)data;
2235 
2236 		// fetch input
2237 		err = message->FindData("input", B_RAW_TYPE, n, &data, &dataSize);
2238 		if(err < B_OK) {
2239 			if(!n) {
2240 				PRINT((
2241 					"* NodeManager::_handleConnectionMade(): no complete entries in message.\n"));
2242 			}
2243 			break;
2244 		}
2245 		if(dataSize < ssize_t(sizeof(media_input))) {
2246 			PRINT((
2247 				"* NodeManager::_handleConnectionMade(): not enough data for input.\n"));
2248 			break;
2249 		}
2250 		input = *(media_input*)data;
2251 
2252 		// look for existing Connection instance
2253 		Connection found;
2254 		err = findConnection(
2255 			output.node.node,
2256 			output.source,
2257 			&found);
2258 		if(err == B_OK) {
2259 			PRINT((
2260 				"  - existing connection for %s -> %s found\n",
2261 				found.outputName(), found.inputName()));
2262 			continue;
2263 		}
2264 
2265 		// instantiate & add Connection
2266 		Connection* con = new Connection(
2267 			m_nextConID++,
2268 			output.node,
2269 			output.source,
2270 			output.name,
2271 			input.node,
2272 			input.destination,
2273 			input.name,
2274 			input.format,
2275 			0);
2276 
2277 		_addConnection(con);
2278 	}
2279 }
2280 
2281 // augments message with source and destination node ID's
2282 inline void NodeManager::_handleConnectionBroken(
2283 	BMessage*											message) {
2284 
2285 	D_METHOD((
2286 		"NodeManager::_handleConnectionBroken()\n"));
2287 	status_t err;
2288 
2289 	// walk the listed connections
2290 	for(int32 n=0;;n++) {
2291 		media_source source;
2292 
2293 		const void* data;
2294 		ssize_t dataSize;
2295 
2296 		// fetch source
2297 		err = message->FindData("source", B_RAW_TYPE, n, &data, &dataSize);
2298 		if(err < B_OK) {
2299 			if(!n) {
2300 				PRINT((
2301 					"* NodeManager::_handleConnectionBroken(): incomplete entry in message.\n"));
2302 			}
2303 			break;
2304 		}
2305 		if(dataSize < ssize_t(sizeof(media_source))) {
2306 			PRINT((
2307 				"* NodeManager::_handleConnectionBroken(): not enough data for source.\n"));
2308 			continue;
2309 		}
2310 		source = *(media_source*)data;
2311 
2312 		// look up the connection +++++ SLOW +++++
2313 		Connection con;
2314 		err = findConnection(source, &con);
2315 		if(err < B_OK) {
2316 			PRINT((
2317 				"* NodeManager::_handleConnectionBroken(): connection not found:\n"
2318 				"  %ld:%ld\n",
2319 				source.port, source.id));
2320 
2321 			// add empty entry to message
2322 			message->AddInt32(_connectionField, 0);
2323 			message->AddInt32(_sourceNodeField, 0);
2324 			message->AddInt32(_destNodeField, 0);
2325 			continue;
2326 		}
2327 
2328 		// add entry to the message
2329 		message->AddInt32(_connectionField, con.id());
2330 		message->AddInt32(_sourceNodeField, con.sourceNode());
2331 		message->AddInt32(_destNodeField, con.destinationNode());
2332 
2333 //		// [e.moon 7nov99] call hook
2334 //		connectionBroken(&con);
2335 
2336 		// home free; delete the connection
2337 		_removeConnection(con);
2338 
2339 	} // for(int32 n ...
2340 }
2341 
2342 inline void
2343 NodeManager::_handleFormatChanged(BMessage *message)
2344 {
2345 	D_METHOD((
2346 		"NodeManager::_handleFormatChanged()\n"));
2347 	status_t err;
2348 
2349 	ssize_t dataSize;
2350 
2351 	// fetch source
2352 	media_source* source;
2353 	err = message->FindData("be:source", B_RAW_TYPE, (const void**)&source, &dataSize);
2354 	if(err < B_OK) {
2355 		PRINT((
2356 			"* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2357 		return;
2358 	}
2359 
2360 	// fetch destination
2361 	media_destination* destination;
2362 	err = message->FindData("be:destination", B_RAW_TYPE, (const void**)&destination, &dataSize);
2363 	if(err < B_OK) {
2364 		PRINT((
2365 			"* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2366 		return;
2367 	}
2368 
2369 	// fetch format
2370 	media_format* format;
2371 	err = message->FindData("be:format", B_RAW_TYPE, (const void**)&format, &dataSize);
2372 	if(err < B_OK) {
2373 		PRINT((
2374 			"* NodeManager::_handleFormatChanged(): incomplete entry in message.\n"));
2375 		return;
2376 	}
2377 
2378 	// find matching connection
2379 	for(con_map::const_iterator it = m_conSourceMap.begin();
2380 		it != m_conSourceMap.end(); ++it) {
2381 		if((*it).second->source() == *source) {
2382 			if((*it).second->destination() != *destination) {
2383 				// connection defunct
2384 				return;
2385 			}
2386 
2387 			// found
2388 			(*it).second->m_format = *format;
2389 
2390 			// attach node IDs to message
2391 			message->AddInt32(_connectionField, (*it).second->id());
2392 			message->AddInt32(_sourceNodeField, (*it).second->sourceNode());
2393 			message->AddInt32(_destNodeField, (*it).second->destinationNode());
2394 
2395 			break;
2396 		}
2397 	}
2398 }
2399 
2400 
2401 // return flags appropriate for an external
2402 // node with the given 'kind'
2403 
2404 inline uint32 NodeManager::_userFlagsForKind(
2405 	uint32												kind) {
2406 
2407 	uint32 f = 0;
2408 	if(
2409 //		kind & B_TIME_SOURCE ||
2410 		kind & B_PHYSICAL_OUTPUT
2411 		// || kind & B_SYSTEM_MIXER [now in initCommonNodes() e.moon 17nov99]
2412 		)
2413 		f |= (NodeRef::NO_START_STOP | NodeRef::NO_SEEK | NodeRef::NO_PREROLL);
2414 
2415 //	// [28sep99 e.moon] physical inputs may not be stopped for now; at
2416 //	// least one sound input node (for emu10k) stops working when requested
2417 //	// to stop.
2418 //	// +++++ should this logic be in initCommonNodes()?
2419 //	if(
2420 //		kind & B_PHYSICAL_INPUT)
2421 //		f |= NodeRef::NO_STOP;
2422 
2423 	return f;
2424 }
2425 
2426 inline uint32 NodeManager::_implFlagsForKind(
2427 	uint32												kind) {
2428 
2429 	return 0;
2430 }
2431 
2432 // [e.moon 28sep99] latency updating
2433 // These methods must set the recording-mode delay for
2434 // any B_RECORDING nodes they handle.
2435 
2436 // +++++ abstract to 'for each' and 'for each from'
2437 //       methods (template or callback?)
2438 
2439 
2440 // refresh cached latency for every node in the given group
2441 // (or all nodes if no group given.)
2442 
2443 inline void NodeManager::_updateLatencies(
2444 	NodeGroup*										group) {
2445 
2446 	ASSERT(IsLocked());
2447 	if(group) {
2448 		ASSERT(group->isLocked());
2449 	}
2450 
2451 	if(group) {
2452 		for(NodeGroup::node_set::iterator it = group->m_nodes.begin();
2453 			it != group->m_nodes.end(); ++it) {
2454 
2455 			(*it)->_updateLatency();
2456 		}
2457 	}
2458 	else {
2459 		for(node_ref_map::iterator it = m_nodeRefMap.begin();
2460 			it != m_nodeRefMap.end(); ++it) {
2461 
2462 			(*it).second->_updateLatency();
2463 		}
2464 	}
2465 }
2466 
2467 // refresh cached latency for every node attached to
2468 // AND INCLUDING the given origin node.
2469 // if 'recurse' is true, affects indirectly attached
2470 // nodes as well.
2471 
2472 
2473 inline void NodeManager::_updateLatenciesFrom(
2474 	NodeRef*											origin,
2475 	bool													recurse) {
2476 
2477 	ASSERT(IsLocked());
2478 
2479 //	PRINT(("### NodeManager::_updateLatenciesFrom()\n"));
2480 
2481 	origin->lock();
2482 	origin->_updateLatency();
2483 	origin->unlock();
2484 
2485 	_lockAllGroups(); // [e.moon 13oct99]
2486 
2487 	_for_each_state st;
2488 	_do_for_each_connected(
2489 		this,
2490 		origin,
2491 		0, // all groups
2492 		recurse,
2493 		mem_fun(&NodeRef::_updateLatency),
2494 		&st);
2495 
2496 	_unlockAllGroups(); // [e.moon 13oct99]
2497 }
2498 
2499 // a bit of unpleasantness [e.moon 13oct99]
2500 void NodeManager::_lockAllGroups() {
2501 
2502 	ASSERT(IsLocked());
2503 	for(node_group_set::iterator it = m_nodeGroupSet.begin();
2504 		it != m_nodeGroupSet.end(); ++it) {
2505 		(*it)->lock();
2506 	}
2507 }
2508 
2509 void NodeManager::_unlockAllGroups() {
2510 	ASSERT(IsLocked());
2511 	for(node_group_set::iterator it = m_nodeGroupSet.begin();
2512 		it != m_nodeGroupSet.end(); ++it) {
2513 		(*it)->unlock();
2514 	}
2515 }
2516 
2517 
2518 // END -- NodeManager.cpp --
2519