1c284bb0fSMatt Madia/*
2c284bb0fSMatt Madia * Copyright (c) 1999-2000, Eric Moon.
3c284bb0fSMatt Madia * All rights reserved.
4c284bb0fSMatt Madia *
5c284bb0fSMatt Madia * Redistribution and use in source and binary forms, with or without
6c284bb0fSMatt Madia * modification, are permitted provided that the following conditions
7c284bb0fSMatt Madia * are met:
8c284bb0fSMatt Madia *
9c284bb0fSMatt Madia * 1. Redistributions of source code must retain the above copyright
10c284bb0fSMatt Madia *    notice, this list of conditions, and the following disclaimer.
11c284bb0fSMatt Madia *
12c284bb0fSMatt Madia * 2. Redistributions in binary form must reproduce the above copyright
13c284bb0fSMatt Madia *    notice, this list of conditions, and the following disclaimer in the
14c284bb0fSMatt Madia *    documentation and/or other materials provided with the distribution.
15c284bb0fSMatt Madia *
16c284bb0fSMatt Madia * 3. The name of the author may not be used to endorse or promote products
17c284bb0fSMatt Madia *    derived from this software without specific prior written permission.
18c284bb0fSMatt Madia *
19c284bb0fSMatt Madia * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20c284bb0fSMatt Madia * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21c284bb0fSMatt Madia * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c284bb0fSMatt Madia * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23c284bb0fSMatt Madia * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24c284bb0fSMatt Madia * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25c284bb0fSMatt Madia * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26c284bb0fSMatt Madia * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27c284bb0fSMatt Madia * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28c284bb0fSMatt Madia * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29c284bb0fSMatt Madia */
30c284bb0fSMatt Madia
31c284bb0fSMatt Madia
32a0795c6fSMarcus Overhagen// NodeManager.cpp
33a0795c6fSMarcus Overhagen
34a0795c6fSMarcus Overhagen#include "NodeManager.h"
35a0795c6fSMarcus Overhagen
36a0795c6fSMarcus Overhagen#include "AddOnHost.h"
37a0795c6fSMarcus Overhagen#include "Connection.h"
38a0795c6fSMarcus Overhagen#include "NodeGroup.h"
39a0795c6fSMarcus Overhagen#include "NodeRef.h"
40a0795c6fSMarcus Overhagen
41a0795c6fSMarcus Overhagen#include <Debug.h>
42a0795c6fSMarcus Overhagen#include <MediaRoster.h>
43a0795c6fSMarcus Overhagen
44a0795c6fSMarcus Overhagen#include <algorithm>
45a0795c6fSMarcus Overhagen#include <cstring>
46a0795c6fSMarcus Overhagen#include <functional>
47a0795c6fSMarcus Overhagen#include <list>
48a0795c6fSMarcus Overhagen#include <set>
49a0795c6fSMarcus Overhagen
50a0795c6fSMarcus Overhagen#include "set_tools.h"
51a0795c6fSMarcus Overhagen#include "functional_tools.h"
52a0795c6fSMarcus Overhagen
53a0795c6fSMarcus Overhagen#include "node_manager_impl.h"
54a0795c6fSMarcus Overhagen
5523e67806SIthamar R. Ademausing namespace std;
5623e67806SIthamar R. Adema
57a0795c6fSMarcus Overhagen__USE_CORTEX_NAMESPACE
58a0795c6fSMarcus Overhagen
59a0795c6fSMarcus Overhagen#define D_METHOD(x) //PRINT (x)
60a0795c6fSMarcus Overhagen#define D_MESSAGE(x) //PRINT (x)
61a0795c6fSMarcus Overhagen#define D_ROSTER(x) //PRINT (x)
62a0795c6fSMarcus Overhagen#define D_LOCK(x) //PRINT (x)
63a0795c6fSMarcus Overhagen
64a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
65a0795c6fSMarcus Overhagen// messaging constants
66a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
67a0795c6fSMarcus Overhagen
68a0795c6fSMarcus Overhagen// B_MEDIA_CONNECTION_BROKEN
69a0795c6fSMarcus Overhagenconst char* const _connectionField = "__connection_id";
70a0795c6fSMarcus Overhagenconst char* const _sourceNodeField = "__source_node_id";
71a0795c6fSMarcus Overhagenconst char* const _destNodeField = "__destination_node_id";
72d363440aSIngo Weinhold
73a0795c6fSMarcus Overhagen
74a0795c6fSMarcus Overhagen
75a0795c6fSMarcus Overhagen
76a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
77a0795c6fSMarcus Overhagen// *** hooks
78a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
79a0795c6fSMarcus Overhagen
80a0795c6fSMarcus Overhagen// [e.moon 7nov99] these hooks are called during processing of
81a0795c6fSMarcus Overhagen// BMediaRoster messages, before any notification is sent to
82a0795c6fSMarcus Overhagen// observers.  For example, if a B_MEDIA_NODES_CREATED message
83a0795c6fSMarcus Overhagen// were received describing 3 new nodes, nodeCreated() would be
84a0795c6fSMarcus Overhagen// called 3 times before the notification was sent.
85a0795c6fSMarcus Overhagen
86a0795c6fSMarcus Overhagenvoid NodeManager::nodeCreated(
87a0795c6fSMarcus Overhagen	NodeRef*											ref) {}
88a0795c6fSMarcus Overhagen
89a0795c6fSMarcus Overhagenvoid NodeManager::nodeDeleted(
90a0795c6fSMarcus Overhagen	const NodeRef*								ref) {}
91d363440aSIngo Weinhold
92a0795c6fSMarcus Overhagenvoid NodeManager::connectionMade(
93a0795c6fSMarcus Overhagen	Connection*										connection) {}
94a0795c6fSMarcus Overhagen
95a0795c6fSMarcus Overhagenvoid NodeManager::connectionBroken(
96a0795c6fSMarcus Overhagen	const Connection*							connection) {}
97a0795c6fSMarcus Overhagen
98a0795c6fSMarcus Overhagenvoid NodeManager::connectionFailed(
99a0795c6fSMarcus Overhagen	const media_output &							output,
100a0795c6fSMarcus Overhagen	const media_input &								input,
101a0795c6fSMarcus Overhagen	const media_format &							format,
102a0795c6fSMarcus Overhagen	status_t error) {}
103a0795c6fSMarcus Overhagen
104a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
105a0795c6fSMarcus Overhagen// helpers
106a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
107a0795c6fSMarcus Overhagen
108a0795c6fSMarcus Overhagenclass _for_each_state {
109a0795c6fSMarcus Overhagenpublic:
110a0795c6fSMarcus Overhagen	// marks nodes visited
111a0795c6fSMarcus Overhagen	set<media_node_id>		visited;
112a0795c6fSMarcus Overhagen};
113a0795c6fSMarcus Overhagen
114a0795c6fSMarcus Overhagen// [e.moon 28sep99] graph crawling
115a0795c6fSMarcus Overhagen// - does NOT apply operation to origin node.
116a0795c6fSMarcus Overhagen// - if inGroup is non-0, visits only nodes in that group.
117a0795c6fSMarcus Overhagen//
118a0795c6fSMarcus Overhagen// [e.moon 13oct99]: no longer supports locking (use _lockAllGroups() to
119a0795c6fSMarcus Overhagen// be sure all nodes are locked, if necessary.)
120a0795c6fSMarcus Overhagen
121a0795c6fSMarcus Overhagentemplate<class Op>
122a0795c6fSMarcus Overhagenvoid _do_for_each_connected(
123a0795c6fSMarcus Overhagen	NodeManager*											manager,
124a0795c6fSMarcus Overhagen	NodeRef*													origin,
125a0795c6fSMarcus Overhagen	NodeGroup*												inGroup,
126a0795c6fSMarcus Overhagen	bool															recurse,
127a0795c6fSMarcus Overhagen	Op																operation,
128a0795c6fSMarcus Overhagen	_for_each_state*									state) {
129d363440aSIngo Weinhold
130a0795c6fSMarcus Overhagen//	PRINT(("### _do_for_each_connected()\n"));
131a0795c6fSMarcus Overhagen
132a0795c6fSMarcus Overhagen	ASSERT(manager->IsLocked());
133a0795c6fSMarcus Overhagen
134a0795c6fSMarcus Overhagen	ASSERT(origin);
135a0795c6fSMarcus Overhagen	ASSERT(state);
136a0795c6fSMarcus Overhagen	status_t err;
137a0795c6fSMarcus Overhagen
138a0795c6fSMarcus Overhagen	if(state->visited.find(origin->id()) != state->visited.end()) {
139a0795c6fSMarcus Overhagen//		PRINT(("### already visited\n"));
140a0795c6fSMarcus Overhagen		// already visited
141a0795c6fSMarcus Overhagen		return;
142a0795c6fSMarcus Overhagen	}
143d363440aSIngo Weinhold
144a0795c6fSMarcus Overhagen	// used to walk connections
145a0795c6fSMarcus Overhagen	vector<Connection>		connections;
146a0795c6fSMarcus Overhagen
147a0795c6fSMarcus Overhagen	// mark visited
148a0795c6fSMarcus Overhagen	state->visited.insert(origin->id());
149a0795c6fSMarcus Overhagen
150a0795c6fSMarcus Overhagen	// walk input connections
151a0795c6fSMarcus Overhagen	origin->getInputConnections(connections);
152a0795c6fSMarcus Overhagen	for(uint32 n = 0; n < connections.size(); ++n) {
153d363440aSIngo Weinhold
154a0795c6fSMarcus Overhagen		if(!connections[n].isValid())
155a0795c6fSMarcus Overhagen			continue;
156d363440aSIngo Weinhold
157a0795c6fSMarcus Overhagen//		PRINT(("# source: %ld\n", connections[n].sourceNode()));
158d363440aSIngo Weinhold
159a0795c6fSMarcus Overhagen		NodeRef* targetRef;
160a0795c6fSMarcus Overhagen		err = manager->getNodeRef(
161a0795c6fSMarcus Overhagen			connections[n].sourceNode(),
162a0795c6fSMarcus Overhagen			&targetRef);
163a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
164a0795c6fSMarcus Overhagen		ASSERT(targetRef);
165d363440aSIngo Weinhold
166a0795c6fSMarcus Overhagen		if(inGroup && targetRef->group() != inGroup) {
167a0795c6fSMarcus Overhagen//			PRINT(("# .group mismatch\n"));
168a0795c6fSMarcus Overhagen			// don't need to visit
169a0795c6fSMarcus Overhagen			return;
170a0795c6fSMarcus Overhagen		}
171d363440aSIngo Weinhold
172a0795c6fSMarcus Overhagen		// invoke operation
173a0795c6fSMarcus Overhagen//		if(lockRef)
174a0795c6fSMarcus Overhagen//			targetRef->lock();
175a0795c6fSMarcus Overhagen		operation(targetRef);
176a0795c6fSMarcus Overhagen//		if(lockRef)
177a0795c6fSMarcus Overhagen//			targetRef->unlock();
178d363440aSIngo Weinhold
179a0795c6fSMarcus Overhagen		// recurse?
180a0795c6fSMarcus Overhagen		if(recurse)
181a0795c6fSMarcus Overhagen			_do_for_each_connected(
182a0795c6fSMarcus Overhagen				manager,
183a0795c6fSMarcus Overhagen				targetRef,
184a0795c6fSMarcus Overhagen				inGroup,
185a0795c6fSMarcus Overhagen				true,
186a0795c6fSMarcus Overhagen				operation,
187a0795c6fSMarcus Overhagen				state);
188a0795c6fSMarcus Overhagen	}
189d363440aSIngo Weinhold
190a0795c6fSMarcus Overhagen	// walk output connections
191a0795c6fSMarcus Overhagen	connections.clear();
192a0795c6fSMarcus Overhagen	origin->getOutputConnections(connections);
193a0795c6fSMarcus Overhagen	for(uint32 n = 0; n < connections.size(); ++n) {
194a0795c6fSMarcus Overhagen//		PRINT(("# dest: %ld\n", connections[n].destinationNode()));
195a0795c6fSMarcus Overhagen
196a0795c6fSMarcus Overhagen		if(!connections[n].isValid())
197a0795c6fSMarcus Overhagen			continue;
198d363440aSIngo Weinhold
199a0795c6fSMarcus Overhagen		NodeRef* targetRef;
200a0795c6fSMarcus Overhagen		err = manager->getNodeRef(
201a0795c6fSMarcus Overhagen			connections[n].destinationNode(),
202a0795c6fSMarcus Overhagen			&targetRef);
203a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
204a0795c6fSMarcus Overhagen		ASSERT(targetRef);
205d363440aSIngo Weinhold
206a0795c6fSMarcus Overhagen		if(inGroup && targetRef->group() != inGroup) {
207a0795c6fSMarcus Overhagen//			PRINT(("# .group mismatch\n"));
208a0795c6fSMarcus Overhagen			// don't need to visit
209a0795c6fSMarcus Overhagen			return;
210a0795c6fSMarcus Overhagen		}
211a0795c6fSMarcus Overhagen
212a0795c6fSMarcus Overhagen		// invoke operation
213a0795c6fSMarcus Overhagen//		if(lockRef)
214a0795c6fSMarcus Overhagen//			targetRef->lock();
215a0795c6fSMarcus Overhagen		operation(targetRef);
216a0795c6fSMarcus Overhagen//		if(lockRef)
217a0795c6fSMarcus Overhagen//			targetRef->unlock();
218d363440aSIngo Weinhold
219a0795c6fSMarcus Overhagen		// recurse?
220a0795c6fSMarcus Overhagen		if(recurse)
221a0795c6fSMarcus Overhagen			_do_for_each_connected(
222a0795c6fSMarcus Overhagen				manager,
223a0795c6fSMarcus Overhagen				targetRef,
224a0795c6fSMarcus Overhagen				inGroup,
225a0795c6fSMarcus Overhagen				true,
226a0795c6fSMarcus Overhagen				operation,
227a0795c6fSMarcus Overhagen				state);
228a0795c6fSMarcus Overhagen	}
229a0795c6fSMarcus Overhagen}
230a0795c6fSMarcus Overhagen
231a0795c6fSMarcus Overhagen// dtor helpers
232a0795c6fSMarcus Overhageninline void NodeManager::_clearGroup(
233a0795c6fSMarcus Overhagen	NodeGroup*										group) {
234a0795c6fSMarcus Overhagen	Autolock _l(group);
235a0795c6fSMarcus Overhagen	D_METHOD((
236a0795c6fSMarcus Overhagen		"NodeManager::_clearGroup()\n"));
237a0795c6fSMarcus Overhagen
238a0795c6fSMarcus Overhagen	// stop group before clearing [10aug99]
239a0795c6fSMarcus Overhagen	group->_stop();
240d363440aSIngo Weinhold
241a0795c6fSMarcus Overhagen	int32 n;
242a0795c6fSMarcus Overhagen	while((n = group->countNodes()) > 0) {
243a0795c6fSMarcus Overhagen		group->removeNode(n-1);
244a0795c6fSMarcus Overhagen	}
245d363440aSIngo Weinhold
246a0795c6fSMarcus Overhagen//	// [e.moon 7nov99] release the group
247a0795c6fSMarcus Overhagen//	status_t err = remove_observer(this, group);
248a0795c6fSMarcus Overhagen//	if(err < B_OK) {
249a0795c6fSMarcus Overhagen//		// spew diagnostics
250a0795c6fSMarcus Overhagen//		PRINT((
251a0795c6fSMarcus Overhagen//			"!!! NodeManager::_clearGroup(): remove_observer(group %ld):\n"
252a0795c6fSMarcus Overhagen//			"    %s\n",
253a0795c6fSMarcus Overhagen//			group->id(),
254a0795c6fSMarcus Overhagen//			strerror(err)));
255d363440aSIngo Weinhold//	}
256a0795c6fSMarcus Overhagen}
257a0795c6fSMarcus Overhagen
258a0795c6fSMarcus Overhageninline void NodeManager::_freeConnection(
259a0795c6fSMarcus Overhagen	Connection*										connection) {
260a0795c6fSMarcus Overhagen	ASSERT(connection);
261a0795c6fSMarcus Overhagen
262a0795c6fSMarcus Overhagen	D_METHOD((
263a0795c6fSMarcus Overhagen		"NodeManager::_freeConnection(%ld)\n", connection->id()));
264a0795c6fSMarcus Overhagen	status_t err;
265a0795c6fSMarcus Overhagen
266a0795c6fSMarcus Overhagen	// break if internal & still valid
267a0795c6fSMarcus Overhagen	if(
268a0795c6fSMarcus Overhagen		connection->isValid() &&
269a0795c6fSMarcus Overhagen		connection->flags() & Connection::INTERNAL &&
270a0795c6fSMarcus Overhagen		!(connection->flags() & Connection::LOCKED)) {
271d363440aSIngo Weinhold
272a0795c6fSMarcus Overhagen		D_METHOD((
273a0795c6fSMarcus Overhagen			"! breaking connection:\n"
274a0795c6fSMarcus Overhagen			"  source node:  %ld\n"
275a0795c6fSMarcus Overhagen			"  source id:    %ld\n"
276a0795c6fSMarcus Overhagen			"  source port:  %ld\n"
277a0795c6fSMarcus Overhagen			"  dest node:    %ld\n"
278a0795c6fSMarcus Overhagen			"  dest id:      %ld\n"
279a0795c6fSMarcus Overhagen			"  dest port:    %ld\n",
280a0795c6fSMarcus Overhagen			connection->sourceNode(),
281a0795c6fSMarcus Overhagen			connection->source().id, connection->source().port,
282a0795c6fSMarcus Overhagen			connection->destinationNode(),
283a0795c6fSMarcus Overhagen			connection->destination().id, connection->destination().port));
284a0795c6fSMarcus Overhagen
285a0795c6fSMarcus Overhagen		// do it
286a0795c6fSMarcus Overhagen		D_ROSTER(("# roster->Disconnect()\n"));
287a0795c6fSMarcus Overhagen		err = roster->Disconnect(
288a0795c6fSMarcus Overhagen			connection->sourceNode(),
289a0795c6fSMarcus Overhagen			connection->source(),
290a0795c6fSMarcus Overhagen			connection->destinationNode(),
291a0795c6fSMarcus Overhagen			connection->destination());
292a0795c6fSMarcus Overhagen
293a0795c6fSMarcus Overhagen		if(err < B_OK) {
294a0795c6fSMarcus Overhagen			D_METHOD((
295a0795c6fSMarcus Overhagen				"!!! BMediaRoster::Disconnect('%s' -> '%s') failed:\n"
296a0795c6fSMarcus Overhagen				"    %s\n",
297a0795c6fSMarcus Overhagen				connection->outputName(), connection->inputName(),
298a0795c6fSMarcus Overhagen				strerror(err)));
299a0795c6fSMarcus Overhagen		}
300a0795c6fSMarcus Overhagen	}
301d363440aSIngo Weinhold
302a0795c6fSMarcus Overhagen	// delete
303a0795c6fSMarcus Overhagen	delete connection;
304a0795c6fSMarcus Overhagen}
305a0795c6fSMarcus Overhagen
306a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
307a0795c6fSMarcus Overhagen// *** ctor/dtor
308a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
309a0795c6fSMarcus Overhagen
310a0795c6fSMarcus Overhagen
311a0795c6fSMarcus OverhagenNodeManager::~NodeManager() {
312a0795c6fSMarcus Overhagen	D_METHOD((
313a0795c6fSMarcus Overhagen		"~NodeManager()\n"));
314a0795c6fSMarcus Overhagen	ASSERT(IsLocked());
315a0795c6fSMarcus Overhagen
316a0795c6fSMarcus Overhagen	// make a list of nodes to be released
317a0795c6fSMarcus Overhagen	list<NodeRef*> deadNodes;
318a0795c6fSMarcus Overhagen
319a0795c6fSMarcus Overhagen	for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
320a0795c6fSMarcus Overhagen		it != m_nodeRefMap.end(); ++it) {
321a0795c6fSMarcus Overhagen		deadNodes.push_back((*it).second);
322a0795c6fSMarcus Overhagen	}
323d363440aSIngo Weinhold
324a0795c6fSMarcus Overhagen	// ungroup all nodes
325d363440aSIngo Weinhold
326a0795c6fSMarcus Overhagen// [e.moon 13oct99] making PPC compiler happy
327a0795c6fSMarcus Overhagen//	for_each(
328a0795c6fSMarcus Overhagen//		m_nodeGroupSet.begin(),
329a0795c6fSMarcus Overhagen//		m_nodeGroupSet.end(),
330a0795c6fSMarcus Overhagen//		bound_method(
331a0795c6fSMarcus Overhagen//			*this,
332a0795c6fSMarcus Overhagen//			&NodeManager::_clearGroup
333a0795c6fSMarcus Overhagen//		)
334a0795c6fSMarcus Overhagen//	);
335a0795c6fSMarcus Overhagen	for(node_group_set::iterator it = m_nodeGroupSet.begin();
336a0795c6fSMarcus Overhagen		it != m_nodeGroupSet.end(); ++it) {
337a0795c6fSMarcus Overhagen		_clearGroup(*it);
338a0795c6fSMarcus Overhagen	}
339d363440aSIngo Weinhold
340a0795c6fSMarcus Overhagen	// delete groups
341a0795c6fSMarcus Overhagen	ptr_set_delete(
342a0795c6fSMarcus Overhagen		m_nodeGroupSet.begin(),
343a0795c6fSMarcus Overhagen		m_nodeGroupSet.end());
344a0795c6fSMarcus Overhagen	m_nodeGroupSet.clear();
345a0795c6fSMarcus Overhagen
346d363440aSIngo Weinhold
347a0795c6fSMarcus Overhagen	// deallocate all connections; disconnect internal nodes
348a0795c6fSMarcus Overhagen// [e.moon 13oct99] making PPC compiler happy
349a0795c6fSMarcus Overhagen//	for_each(
350a0795c6fSMarcus Overhagen//		m_conSourceMap.begin(),
351a0795c6fSMarcus Overhagen//		m_conSourceMap.end(),
352a0795c6fSMarcus Overhagen//		unary_map_function(
353a0795c6fSMarcus Overhagen//			m_conSourceMap,
354a0795c6fSMarcus Overhagen//			bound_method(
355a0795c6fSMarcus Overhagen//				*this,
356a0795c6fSMarcus Overhagen//				&NodeManager::_freeConnection
357a0795c6fSMarcus Overhagen//			)
358a0795c6fSMarcus Overhagen//		)
359a0795c6fSMarcus Overhagen//	);
360a0795c6fSMarcus Overhagen	for(con_map::iterator it = m_conSourceMap.begin();
361a0795c6fSMarcus Overhagen		it != m_conSourceMap.end(); ++it) {
362a0795c6fSMarcus Overhagen		_freeConnection((*it).second);
363a0795c6fSMarcus Overhagen	}
364a0795c6fSMarcus Overhagen	m_conSourceMap.clear();
365a0795c6fSMarcus Overhagen	m_conDestinationMap.clear();
366d363440aSIngo Weinhold
367a0795c6fSMarcus Overhagen	// release all nodes
368a0795c6fSMarcus Overhagen	for(list<NodeRef*>::const_iterator it = deadNodes.begin();
369a0795c6fSMarcus Overhagen		it != deadNodes.end(); ++it) {
370a0795c6fSMarcus Overhagen		(*it)->release();
371a0795c6fSMarcus Overhagen	}
372d363440aSIngo Weinhold
373a0795c6fSMarcus Overhagen	if(m_nodeRefMap.size()) {
374d363440aSIngo Weinhold		// +++++ nodes will only remain if they have observers; cope!
375a0795c6fSMarcus Overhagen		PRINT(("*** %ld nodes remaining!\n", m_nodeRefMap.size()));
376a0795c6fSMarcus Overhagen
377a0795c6fSMarcus Overhagen		deadNodes.clear();
378a0795c6fSMarcus Overhagen		for(node_ref_map::const_iterator it = m_nodeRefMap.begin();
379a0795c6fSMarcus Overhagen			it != m_nodeRefMap.end(); ++it)
380a0795c6fSMarcus Overhagen				deadNodes.push_back((*it).second);
381a0795c6fSMarcus Overhagen
382a0795c6fSMarcus Overhagen		ptr_set_delete(
383a0795c6fSMarcus Overhagen			deadNodes.begin(),
384d363440aSIngo Weinhold			deadNodes.end());
385a0795c6fSMarcus Overhagen	}
386d363440aSIngo Weinhold
387a0795c6fSMarcus Overhagen//	for_each(
388a0795c6fSMarcus Overhagen//		m_nodeRefMap.begin(),
389a0795c6fSMarcus Overhagen//		m_nodeRefMap.end(),
390a0795c6fSMarcus Overhagen//		unary_map_function(
391a0795c6fSMarcus Overhagen//			m_nodeRefMap,
392a0795c6fSMarcus Overhagen//			mem_fun(
393a0795c6fSMarcus Overhagen//				&NodeRef::release
394a0795c6fSMarcus Overhagen//			)
395a0795c6fSMarcus Overhagen//		)
396a0795c6fSMarcus Overhagen//	);
397d363440aSIngo Weinhold//
398a0795c6fSMarcus Overhagen//	// delete all nodes
399a0795c6fSMarcus Overhagen//	ptr_map_delete(
400a0795c6fSMarcus Overhagen//		m_nodeRefMap.begin(),
401a0795c6fSMarcus Overhagen//		m_nodeRefMap.end());
402d363440aSIngo Weinhold//
403a0795c6fSMarcus Overhagen//
404a0795c6fSMarcus Overhagen//	PRINT((
405a0795c6fSMarcus Overhagen//		"~NodeManager() done\n"));
406a0795c6fSMarcus Overhagen//
407a0795c6fSMarcus Overhagen}
408a0795c6fSMarcus Overhagen
409a0795c6fSMarcus Overhagenconst char* const			NodeManager::s_defaultGroupPrefix = "No Name";
410a0795c6fSMarcus Overhagenconst char* const			NodeManager::s_timeSourceGroup = "Time Sources";
411a0795c6fSMarcus Overhagenconst char* const			NodeManager::s_audioInputGroup = "System Audio Input";
412a0795c6fSMarcus Overhagenconst char* const			NodeManager::s_videoInputGroup = "System Video Input";
413a0795c6fSMarcus Overhagenconst char* const			NodeManager::s_audioMixerGroup = "System Audio Mixer";
414a0795c6fSMarcus Overhagenconst char* const			NodeManager::s_videoOutputGroup = "System Video Output";
415a0795c6fSMarcus Overhagen
416a0795c6fSMarcus OverhagenNodeManager::NodeManager(
417a0795c6fSMarcus Overhagen	bool													useAddOnHost) :
418a0795c6fSMarcus Overhagen
419a0795c6fSMarcus Overhagen	ObservableLooper("NodeManager"),
420a0795c6fSMarcus Overhagen	roster(BMediaRoster::Roster()),
421a0795c6fSMarcus Overhagen	m_audioInputNode(0),
422a0795c6fSMarcus Overhagen	m_videoInputNode(0),
423a0795c6fSMarcus Overhagen	m_audioMixerNode(0),
424a0795c6fSMarcus Overhagen	m_audioOutputNode(0),
425a0795c6fSMarcus Overhagen	m_videoOutputNode(0),
426a0795c6fSMarcus Overhagen	m_nextConID(1),
427a0795c6fSMarcus Overhagen	m_existingNodesInit(false),
428a0795c6fSMarcus Overhagen	m_useAddOnHost(useAddOnHost) {
429a0795c6fSMarcus Overhagen
430a0795c6fSMarcus Overhagen	D_METHOD((
431a0795c6fSMarcus Overhagen		"NodeManager()\n"));
432a0795c6fSMarcus Overhagen
433a0795c6fSMarcus Overhagen	ASSERT(roster);
434d363440aSIngo Weinhold
435a0795c6fSMarcus Overhagen	// create refs for common nodes
436a0795c6fSMarcus Overhagen	_initCommonNodes();
437a0795c6fSMarcus Overhagen
438d363440aSIngo Weinhold	// start the looper
439a0795c6fSMarcus Overhagen	Run();
440d363440aSIngo Weinhold
441a0795c6fSMarcus Overhagen	// initialize connection to the media roster
442dfd1fe13SAxel Dörfler	D_ROSTER(("# roster->StartWatching(%p)\n", this));
443dfd1fe13SAxel Dörfler	roster->StartWatching(BMessenger(this));
444a0795c6fSMarcus Overhagen}
445a0795c6fSMarcus Overhagen
446a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
447a0795c6fSMarcus Overhagen// *** operations
448a0795c6fSMarcus Overhagen// -------------------------------------------------------- //
449a0795c6fSMarcus Overhagen
450a0795c6fSMarcus Overhagen// * ACCESS
451a0795c6fSMarcus Overhagen
452a0795c6fSMarcus Overhagen// fetches NodeRef corresponding to a given ID; returns
453a0795c6fSMarcus Overhagen// B_BAD_VALUE if no matching entry was found (and writes
454a0795c6fSMarcus Overhagen// a 0 into the provided pointer.)
455a0795c6fSMarcus Overhagen
456a0795c6fSMarcus Overhagenstatus_t NodeManager::getNodeRef(
457a0795c6fSMarcus Overhagen	media_node_id									id,
458a0795c6fSMarcus Overhagen	NodeRef**											outRef) const {
459a0795c6fSMarcus Overhagen	Autolock _l(this);
460a0795c6fSMarcus Overhagen
461a0795c6fSMarcus Overhagen	D_METHOD((
462a0795c6fSMarcus Overhagen		"NodeManager::getNodeRef(%ld)\n", id));
463a0795c6fSMarcus Overhagen
464a0795c6fSMarcus Overhagen	node_ref_map::const_iterator it = m_nodeRefMap.find(id);
465a0795c6fSMarcus Overhagen	if(it == m_nodeRefMap.end()) {
466a0795c6fSMarcus Overhagen		*outRef = 0;
467a0795c6fSMarcus Overhagen		return B_BAD_VALUE;
468a0795c6fSMarcus Overhagen	}
469d363440aSIngo Weinhold
470a0795c6fSMarcus Overhagen	*outRef = (*it).second;
471a0795c6fSMarcus Overhagen	return B_OK;
472a0795c6fSMarcus Overhagen}
473a0795c6fSMarcus Overhagen
474d363440aSIngo Weinhold// [13aug99]
475a0795c6fSMarcus Overhagen// fetches Connection corresponding to a given source/destination
476a0795c6fSMarcus Overhagen// on a given node.  Returns an invalid connection and B_BAD_VALUE
477a0795c6fSMarcus Overhagen// if no matching connection was found.
478d363440aSIngo Weinhold
479a0795c6fSMarcus Overhagenstatus_t NodeManager::findConnection(
480a0795c6fSMarcus Overhagen	media_node_id									node,
481a0795c6fSMarcus Overhagen	const media_source&						source,
482a0795c6fSMarcus Overhagen	Connection*										outConnection) const {
483a0795c6fSMarcus Overhagen	Autolock _l(this);
484d363440aSIngo Weinhold
485a0795c6fSMarcus Overhagen	D_METHOD((
486a0795c6fSMarcus Overhagen		"NodeManager::findConnection()\n"));
487a0795c6fSMarcus Overhagen	ASSERT(source != media_source::null);
488d363440aSIngo Weinhold
489a0795c6fSMarcus Overhagen	con_map::const_iterator it = m_conSourceMap.lower_bound(node);
490a0795c6fSMarcus Overhagen	con_map::const_iterator itEnd = m_conSourceMap.upper_bound(node);
491a0795c6fSMarcus Overhagen	for(; it != itEnd; ++it)
492a0795c6fSMarcus Overhagen		if((*it).second->source() == source) {
493a0795c6fSMarcus Overhagen			// copy connection
494a0795c6fSMarcus Overhagen			*outConnection = *((*it).second);
495a0795c6fSMarcus Overhagen			return B_OK;
496a0795c6fSMarcus Overhagen		}
497d363440aSIngo Weinhold
498a0795c6fSMarcus Overhagen	*outConnection = Connection();
499a0795c6fSMarcus Overhagen	return B_BAD_VALUE;
500a0795c6fSMarcus Overhagen}
501d363440aSIngo Weinhold
502a0795c6fSMarcus Overhagenstatus_t NodeManager::findConnection(
503a0795c6fSMarcus Overhagen	media_node_id									node,
504a0795c6fSMarcus Overhagen	const media_destination&			destination,
505a0795c6fSMarcus Overhagen	Connection*										outConnection) const {
506a0795c6fSMarcus Overhagen	Autolock _l(this);
507d363440aSIngo Weinhold
508a0795c6fSMarcus Overhagen	D_METHOD((
509a0795c6fSMarcus Overhagen		"NodeManager::findConnection()\n"));
510a0795c6fSMarcus Overhagen	ASSERT(destination != media_destination::null);
511d363440aSIngo Weinhold
512a0795c6fSMarcus Overhagen	con_map::const_iterator it = m_conDestinationMap.lower_bound(node);
513a0795c6fSMarcus Overhagen	con_map::const_iterator itEnd = m_conDestinationMap.upper_bound(node);
514a0795c6fSMarcus Overhagen	for(; it != itEnd; ++it)
515a0795c6fSMarcus Overhagen		if((*it).second->destination() == destination) {
516a0795c6fSMarcus Overhagen			// copy connection
517a0795c6fSMarcus Overhagen			*outConnection = *((*it).second);
518a0795c6fSMarcus Overhagen			return B_OK;
519a0795c6fSMarcus Overhagen		}
520d363440aSIngo Weinhold
521a0795c6fSMarcus Overhagen	*outConnection = Connection();
522a0795c6fSMarcus Overhagen	return B_BAD_VALUE;
523a0795c6fSMarcus Overhagen}
524a0795c6fSMarcus Overhagen
525a0795c6fSMarcus Overhagen// [e.moon 28sep99]
526a0795c6fSMarcus Overhagen// fetches a Connection matching the given source and destination
527a0795c6fSMarcus Overhagen// nodes.  Returns an invalid connection and B_BAD_VALUE if
528a0795c6fSMarcus Overhagen// no matching connection was found
529d363440aSIngo Weinhold
530a0795c6fSMarcus Overhagenstatus_t NodeManager::findConnection(
531a0795c6fSMarcus Overhagen	media_node_id									sourceNode,
532a0795c6fSMarcus Overhagen	media_node_id									destinationNode,
533a0795c6fSMarcus Overhagen	Connection*										outConnection) const {
534a0795c6fSMarcus Overhagen	Autolock _l(this);
535a0795c6fSMarcus Overhagen
536a0795c6fSMarcus Overhagen	D_METHOD((
537a0795c6fSMarcus Overhagen		"NodeManager::findConnection(source %ld, dest %ld)\n", sourceNode, destinationNode));
538d363440aSIngo Weinhold
539a0795c6fSMarcus Overhagen	con_map::const_iterator it = m_conSourceMap.lower_bound(sourceNode);
540a0795c6fSMarcus Overhagen	con_map::const_iterator itEnd = m_conSourceMap.upper_bound(sourceNode);
541a0795c6fSMarcus Overhagen	for(; it != itEnd; ++it) {
542a0795c6fSMarcus Overhagen		if((*it).second->destinationNode() == destinationNode) {
543a0795c6fSMarcus Overhagen			*outConnection = *((*it).second);
544a0795c6fSMarcus Overhagen			return B_OK;
545a0795c6fSMarcus Overhagen		}
546a0795c6fSMarcus Overhagen	}
547d363440aSIngo Weinhold
548a0795c6fSMarcus Overhagen	*outConnection = Connection();
549a0795c6fSMarcus Overhagen	return B_BAD_VALUE;
550a0795c6fSMarcus Overhagen}
551a0795c6fSMarcus Overhagen
552a0795c6fSMarcus Overhagen// [e.moon 28sep99]
553a0795c6fSMarcus Overhagen// tries to find a route from 'nodeA' to 'nodeB'; returns
554a0795c6fSMarcus Overhagen// true if one exists, false if not.
555a0795c6fSMarcus Overhagen
556a0795c6fSMarcus Overhagenclass NodeManager::_find_route_state {
557a0795c6fSMarcus Overhagenpublic:
558a0795c6fSMarcus Overhagen	set<media_node_id>						visited;
559a0795c6fSMarcus Overhagen};
560a0795c6fSMarcus Overhagen
561a0795c6fSMarcus Overhagenbool NodeManager::findRoute(
562a0795c6fSMarcus Overhagen	media_node_id									nodeA,
563a0795c6fSMarcus Overhagen	media_node_id									nodeB) {
564a0795c6fSMarcus Overhagen	Autolock _l(this);
565d363440aSIngo Weinhold
566a0795c6fSMarcus Overhagen	D_METHOD((
567a0795c6fSMarcus Overhagen		"NodeManager::findRoute(%ld, %ld)\n", nodeA, nodeB));
568a0795c6fSMarcus Overhagen	status_t err;
569d363440aSIngo Weinhold
570a0795c6fSMarcus Overhagen	NodeRef* ref;
571a0795c6fSMarcus Overhagen	err = getNodeRef(nodeA, &ref);
572a0795c6fSMarcus Overhagen	if(err < B_OK) {
573a0795c6fSMarcus Overhagen		PRINT((
5741a7bcf69SOliver Tappe			"!!! NodeManager::findRoute(%" B_PRId32 ", %" B_PRId32
5751a7bcf69SOliver Tappe			"): no ref for node %" B_PRId32 "\n", nodeA, nodeB, nodeA));
576a0795c6fSMarcus Overhagen		return false;
577a0795c6fSMarcus Overhagen	}
578d363440aSIngo Weinhold
579a0795c6fSMarcus Overhagen	_find_route_state st;
580d363440aSIngo Weinhold	return _find_route_recurse(ref, nodeB, &st);
581a0795c6fSMarcus Overhagen}
582a0795c6fSMarcus Overhagen
583a0795c6fSMarcus Overhagen// implementation of above
584a0795c6fSMarcus Overhagen
585a0795c6fSMarcus Overhagenbool NodeManager::_find_route_recurse(
586a0795c6fSMarcus Overhagen	NodeRef*													origin,
587a0795c6fSMarcus Overhagen	media_node_id											target,
588a0795c6fSMarcus Overhagen	_find_route_state*								state) {
589d363440aSIngo Weinhold
590a0795c6fSMarcus Overhagen	ASSERT(IsLocked());
591a0795c6fSMarcus Overhagen	ASSERT(origin);
592a0795c6fSMarcus Overhagen	ASSERT(state);
593a0795c6fSMarcus Overhagen	status_t err;
594d363440aSIngo Weinhold
595a0795c6fSMarcus Overhagen	// node already visited?
596a0795c6fSMarcus Overhagen	if(state->visited.find(origin->id()) != state->visited.end()) {
597a0795c6fSMarcus Overhagen		return false;
598a0795c6fSMarcus Overhagen	}
599d363440aSIngo Weinhold
600a0795c6fSMarcus Overhagen	// mark node visited
601a0795c6fSMarcus Overhagen	state->visited.insert(origin->id());
602a0795c6fSMarcus Overhagen
603a0795c6fSMarcus Overhagen	vector<Connection> connections;
604a0795c6fSMarcus Overhagen
605a0795c6fSMarcus Overhagen	// walk input connections
606a0795c6fSMarcus Overhagen	origin->getInputConnections(connections);
607a0795c6fSMarcus Overhagen	for(uint32 n = 0; n < connections.size(); ++n) {
608a0795c6fSMarcus Overhagen
609a0795c6fSMarcus Overhagen		if(!connections[n].isValid())
610a0795c6fSMarcus Overhagen			continue;
611d363440aSIngo Weinhold
612a0795c6fSMarcus Overhagen		// test against target
613a0795c6fSMarcus Overhagen		if(connections[n].sourceNode() == target)
614a0795c6fSMarcus Overhagen			return true; // SUCCESS
615a0795c6fSMarcus Overhagen
616a0795c6fSMarcus Overhagen		// recurse
617a0795c6fSMarcus Overhagen		NodeRef* ref;
618a0795c6fSMarcus Overhagen		err = getNodeRef(
619a0795c6fSMarcus Overhagen			connections[n].sourceNode(),
620a0795c6fSMarcus Overhagen			&ref);
621a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
622a0795c6fSMarcus Overhagen		ASSERT(ref);
623d363440aSIngo Weinhold
624a0795c6fSMarcus Overhagen		if(_find_route_recurse(
625a0795c6fSMarcus Overhagen			ref,
626a0795c6fSMarcus Overhagen			target,
627a0795c6fSMarcus Overhagen			state))
628a0795c6fSMarcus Overhagen			return true; // SUCCESS
629a0795c6fSMarcus Overhagen	}
630d363440aSIngo Weinhold
631a0795c6fSMarcus Overhagen	// walk output connections
632a0795c6fSMarcus Overhagen	connections.clear();
633a0795c6fSMarcus Overhagen	origin->getOutputConnections(connections);
634a0795c6fSMarcus Overhagen	for(uint32 n = 0; n < connections.size(); ++n) {
635a0795c6fSMarcus Overhagen
636a0795c6fSMarcus Overhagen		if(!connections[n].isValid())
637a0795c6fSMarcus Overhagen			continue;
638d363440aSIngo Weinhold
639a0795c6fSMarcus Overhagen		// test against target
640a0795c6fSMarcus Overhagen		if(connections[n].destinationNode() == target)
641a0795c6fSMarcus Overhagen			return true; // SUCCESS
642a0795c6fSMarcus Overhagen
643a0795c6fSMarcus Overhagen		// recurse
644a0795c6fSMarcus Overhagen		NodeRef* ref;
645a0795c6fSMarcus Overhagen		err = getNodeRef(
646a0795c6fSMarcus Overhagen			connections[n].destinationNode(),
647a0795c6fSMarcus Overhagen			&ref);
648a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
649a0795c6fSMarcus Overhagen		ASSERT(ref);
650d363440aSIngo Weinhold
651a0795c6fSMarcus Overhagen		if(_find_route_recurse(
652a0795c6fSMarcus Overhagen			ref,
653a0795c6fSMarcus Overhagen			target,
654a0795c6fSMarcus Overhagen			state))
655a0795c6fSMarcus Overhagen			return true; // SUCCESS
656a0795c6fSMarcus Overhagen	}
657a0795c6fSMarcus Overhagen
658a0795c6fSMarcus Overhagen	return false; // FAILED
659a0795c6fSMarcus Overhagen}
660a0795c6fSMarcus Overhagen
661a0795c6fSMarcus Overhagen
662a0795c6fSMarcus Overhagen
663a0795c6fSMarcus Overhagen// fetches Connection corresponding to a given source or
664a0795c6fSMarcus Overhagen// destination; Returns an invalid connection and B_BAD_VALUE if
665a0795c6fSMarcus Overhagen// none found.
666a0795c6fSMarcus Overhagen// * Note: this is the slowest possible way to look up a
667a0795c6fSMarcus Overhagen//   connection.  Since the low-level source/destination
668a0795c6fSMarcus Overhagen//   structures don't include a node ID, and a destination
669a0795c6fSMarcus Overhagen//   port can differ from its node's control port, a linear
670a0795c6fSMarcus Overhagen//   search of all known connections is performed.  Only
671a0795c6fSMarcus Overhagen//   use these methods if you have no clue what node the
672a0795c6fSMarcus Overhagen//   connection corresponds to.
673a0795c6fSMarcus Overhagen
674a0795c6fSMarcus Overhagenstatus_t NodeManager::findConnection(
675a0795c6fSMarcus Overhagen	const media_source&						source,
676a0795c6fSMarcus Overhagen	Connection*										outConnection) const {
677a0795c6fSMarcus Overhagen	Autolock _l(this);
678d363440aSIngo Weinhold
679a0795c6fSMarcus Overhagen	D_METHOD((
680a0795c6fSMarcus Overhagen		"NodeManager::findConnection()\n"));
681a0795c6fSMarcus Overhagen	ASSERT(source != media_source::null);
682a0795c6fSMarcus Overhagen
683a0795c6fSMarcus Overhagen	for(con_map::const_iterator it = m_conSourceMap.begin();
684a0795c6fSMarcus Overhagen		it != m_conSourceMap.end(); ++it) {
685a0795c6fSMarcus Overhagen		if((*it).second->source() == source) {
686a0795c6fSMarcus Overhagen			// copy connection
687a0795c6fSMarcus Overhagen			*outConnection = *((*it).second);
688a0795c6fSMarcus Overhagen			return B_OK;
689a0795c6fSMarcus Overhagen		}
690a0795c6fSMarcus Overhagen	}
691a0795c6fSMarcus Overhagen
692a0795c6fSMarcus Overhagen	*outConnection = Connection();
693a0795c6fSMarcus Overhagen	return B_BAD_VALUE;
694a0795c6fSMarcus Overhagen}
695a0795c6fSMarcus Overhagen
696a0795c6fSMarcus Overhagenstatus_t NodeManager::findConnection(
697a0795c6fSMarcus Overhagen	const media_destination&			destination,
698a0795c6fSMarcus Overhagen	Connection*										outConnection) const {
699a0795c6fSMarcus Overhagen	Autolock _l(this);
700d363440aSIngo Weinhold
701a0795c6fSMarcus Overhagen	D_METHOD((
702a0795c6fSMarcus Overhagen		"NodeManager::findConnection()\n"));
703a0795c6fSMarcus Overhagen	ASSERT(destination != media_destination::null);
704a0795c6fSMarcus Overhagen
705a0795c6fSMarcus Overhagen	for(con_map::const_iterator it = m_conDestinationMap.begin();
706a0795c6fSMarcus Overhagen		it != m_conDestinationMap.end(); ++it) {
707a0795c6fSMarcus Overhagen		if((*it).second->destination() == destination) {
708a0795c6fSMarcus Overhagen			// copy connection
709a0795c6fSMarcus Overhagen			*outConnection = *((*it).second);
710a0795c6fSMarcus Overhagen			return B_OK;
711a0795c6fSMarcus Overhagen		}
712a0795c6fSMarcus Overhagen	}
713a0795c6fSMarcus Overhagen
714a0795c6fSMarcus Overhagen	*outConnection = Connection();
715a0795c6fSMarcus Overhagen	return B_BAD_VALUE;
716a0795c6fSMarcus Overhagen}
717a0795c6fSMarcus Overhagen
718a0795c6fSMarcus Overhagen
719a0795c6fSMarcus Overhagen// fetch NodeRefs for system nodes (if a particular node doesn't
720a0795c6fSMarcus Overhagen// exist, these methods return 0)
721d363440aSIngo Weinhold
722a0795c6fSMarcus OverhagenNodeRef* NodeManager::audioInputNode() const {
723a0795c6fSMarcus Overhagen	Autolock _l(this);
724a0795c6fSMarcus Overhagen	return m_audioInputNode;
725a0795c6fSMarcus Overhagen}
726a0795c6fSMarcus OverhagenNodeRef* NodeManager::videoInputNode() const {
727a0795c6fSMarcus Overhagen	Autolock _l(this);
728a0795c6fSMarcus Overhagen	return m_videoInputNode;
729a0795c6fSMarcus Overhagen}
730a0795c6fSMarcus OverhagenNodeRef* NodeManager::audioMixerNode() const {
731a0795c6fSMarcus Overhagen	Autolock _l(this);
732a0795c6fSMarcus Overhagen	return m_audioMixerNode;
733a0795c6fSMarcus Overhagen}
734a0795c6fSMarcus OverhagenNodeRef* NodeManager::audioOutputNode() const {
735a0795c6fSMarcus Overhagen	Autolock _l(this);
736a0795c6fSMarcus Overhagen	return m_audioOutputNode;
737a0795c6fSMarcus Overhagen}
738a0795c6fSMarcus OverhagenNodeRef* NodeManager::videoOutputNode() const {
739a0795c6fSMarcus Overhagen	Autolock _l(this);
740a0795c6fSMarcus Overhagen	return m_videoOutputNode;
741a0795c6fSMarcus Overhagen}
742a0795c6fSMarcus Overhagen
743a0795c6fSMarcus Overhagen// fetch groups by index
744a0795c6fSMarcus Overhagen// - you can write-lock the manager during sets of calls to these methods;
745a0795c6fSMarcus Overhagen//   this ensures that the group set won't change.  The methods do lock
746a0795c6fSMarcus Overhagen//   the group internally, so locking isn't explicitly required.
747d363440aSIngo Weinhold
748a0795c6fSMarcus Overhagenuint32 NodeManager::countGroups() const {
749a0795c6fSMarcus Overhagen	Autolock _l(this);
750a0795c6fSMarcus Overhagen	D_METHOD((
751a0795c6fSMarcus Overhagen		"NodeManager::countGroups()\n"));
752a0795c6fSMarcus Overhagen
753a0795c6fSMarcus Overhagen	return m_nodeGroupSet.size();
754a0795c6fSMarcus Overhagen}
755a0795c6fSMarcus Overhagen
756a0795c6fSMarcus OverhagenNodeGroup* NodeManager::groupAt(
757a0795c6fSMarcus Overhagen	uint32												index) const {
758a0795c6fSMarcus Overhagen	Autolock _l(this);
759a0795c6fSMarcus Overhagen	D_METHOD((
760a0795c6fSMarcus Overhagen		"NodeManager::groupAt()\n"));
761a0795c6fSMarcus Overhagen
762a0795c6fSMarcus Overhagen	return (index < m_nodeGroupSet.size()) ?
763a0795c6fSMarcus Overhagen		m_nodeGroupSet[index] :
764a0795c6fSMarcus Overhagen		0;
765a0795c6fSMarcus Overhagen}
766a0795c6fSMarcus Overhagen
767a0795c6fSMarcus Overhagen// look up a group by unique ID; returns B_BAD_VALUE if no
768a0795c6fSMarcus Overhagen// matching group was found
769d363440aSIngo Weinhold
770a0795c6fSMarcus Overhagenclass match_group_by_id :
771a0795c6fSMarcus Overhagen	public binary_function<const NodeGroup*, uint32, bool> {
772a0795c6fSMarcus Overhagenpublic:
773a0795c6fSMarcus Overhagen	bool operator()(const NodeGroup* group, uint32 id) const {
774a0795c6fSMarcus Overhagen		return group->id() == id;
775a0795c6fSMarcus Overhagen	}
776a0795c6fSMarcus Overhagen};
777a0795c6fSMarcus Overhagen
778a0795c6fSMarcus Overhagenstatus_t NodeManager::findGroup(
779a0795c6fSMarcus Overhagen	uint32												id,
780a0795c6fSMarcus Overhagen	NodeGroup**										outGroup) const {
781a0795c6fSMarcus Overhagen	Autolock _l(this);
782a0795c6fSMarcus Overhagen	D_METHOD((
783a0795c6fSMarcus Overhagen		"NodeManager::findGroup(id)\n"));
784a0795c6fSMarcus Overhagen
785a0795c6fSMarcus Overhagen	node_group_set::const_iterator it =
786a0795c6fSMarcus Overhagen		find_if(
787a0795c6fSMarcus Overhagen			m_nodeGroupSet.begin(),
788a0795c6fSMarcus Overhagen			m_nodeGroupSet.end(),
789a0795c6fSMarcus Overhagen			bind2nd(match_group_by_id(), id)
790a0795c6fSMarcus Overhagen		);
791d363440aSIngo Weinhold
792a0795c6fSMarcus Overhagen	if(it == m_nodeGroupSet.end()) {
793a0795c6fSMarcus Overhagen		*outGroup = 0;
794a0795c6fSMarcus Overhagen		return B_BAD_VALUE;
795a0795c6fSMarcus Overhagen	}
796d363440aSIngo Weinhold
797a0795c6fSMarcus Overhagen	*outGroup = *it;
798a0795c6fSMarcus Overhagen	return B_OK;
799a0795c6fSMarcus Overhagen}
800a0795c6fSMarcus Overhagen
801a0795c6fSMarcus Overhagen// look up a group by name; returns B_NAME_NOT_FOUND if
802a0795c6fSMarcus Overhagen// no group matching the name was found.
803a0795c6fSMarcus Overhagen
804a0795c6fSMarcus Overhagenclass match_group_by_name :
805a0795c6fSMarcus Overhagen	public binary_function<const NodeGroup*, const char*, bool> {
806a0795c6fSMarcus Overhagenpublic:
807a0795c6fSMarcus Overhagen	bool operator()(const NodeGroup* group, const char* name) const {
808a0795c6fSMarcus Overhagen		return !strcmp(group->name(), name);
809a0795c6fSMarcus Overhagen	}
810a0795c6fSMarcus Overhagen};
811a0795c6fSMarcus Overhagen
812a0795c6fSMarcus Overhagenstatus_t NodeManager::findGroup(
813a0795c6fSMarcus Overhagen	const char*										name,
814a0795c6fSMarcus Overhagen	NodeGroup**										outGroup) const {
815a0795c6fSMarcus Overhagen	Autolock _l(this);
816a0795c6fSMarcus Overhagen	D_METHOD((
817a0795c6fSMarcus Overhagen		"NodeManager::findGroup(name)\n"));
818a0795c6fSMarcus Overhagen
819a0795c6fSMarcus Overhagen	node_group_set::const_iterator it =
820a0795c6fSMarcus Overhagen		find_if(
821a0795c6fSMarcus Overhagen			m_nodeGroupSet.begin(),
822a0795c6fSMarcus Overhagen			m_nodeGroupSet.end(),
823a0795c6fSMarcus Overhagen			bind2nd(match_group_by_name(), name)
824a0795c6fSMarcus Overhagen		);
825d363440aSIngo Weinhold
826a0795c6fSMarcus Overhagen	if(it == m_nodeGroupSet.end()) {
827a0795c6fSMarcus Overhagen		*outGroup = 0;
828a0795c6fSMarcus Overhagen		return B_BAD_VALUE;
829a0795c6fSMarcus Overhagen	}
830d363440aSIngo Weinhold
831a0795c6fSMarcus Overhagen	*outGroup = *it;
832a0795c6fSMarcus Overhagen	return B_OK;
833a0795c6fSMarcus Overhagen}
834a0795c6fSMarcus Overhagen
835a0795c6fSMarcus Overhagen// merge the given source group to the given destination;
836a0795c6fSMarcus Overhagen// empties and releases the source group
837d363440aSIngo Weinhold
838a0795c6fSMarcus Overhagenstatus_t NodeManager::mergeGroups(
839a0795c6fSMarcus Overhagen	NodeGroup*										sourceGroup,
840a0795c6fSMarcus Overhagen	NodeGroup*										destinationGroup) {
841a0795c6fSMarcus Overhagen	Autolock _l(this);
842d363440aSIngo Weinhold	D_METHOD((
843d363440aSIngo Weinhold		"NodeManager::mergeGroups(name)\n"));
844a0795c6fSMarcus Overhagen
845a0795c6fSMarcus Overhagen	status_t err;
846d363440aSIngo Weinhold
847d363440aSIngo Weinhold	// [5feb00 c.lenz] already merged
848d363440aSIngo Weinhold	if(sourceGroup->id() == destinationGroup->id())
849d363440aSIngo Weinhold		return B_OK;
850a0795c6fSMarcus Overhagen
851a0795c6fSMarcus Overhagen	if(sourceGroup->isReleased() || destinationGroup->isReleased())
852a0795c6fSMarcus Overhagen		return B_NOT_ALLOWED;
853d363440aSIngo Weinhold
854a0795c6fSMarcus Overhagen	for(uint32 n = sourceGroup->countNodes(); n; --n) {
855a0795c6fSMarcus Overhagen		NodeRef* node = sourceGroup->nodeAt(n-1);
856a0795c6fSMarcus Overhagen		ASSERT(node);
857a0795c6fSMarcus Overhagen		err = sourceGroup->removeNode(n-1);
858a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
859a0795c6fSMarcus Overhagen		err = destinationGroup->addNode(node);
860a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
861a0795c6fSMarcus Overhagen	}
862d363440aSIngo Weinhold
863a0795c6fSMarcus Overhagen	// [7nov99 e.moon] delete the source group
864a0795c6fSMarcus Overhagen	_removeGroup(sourceGroup);
865a0795c6fSMarcus Overhagen	sourceGroup->release();
866d363440aSIngo Weinhold
867a0795c6fSMarcus Overhagen	return B_OK;
868a0795c6fSMarcus Overhagen}
869a0795c6fSMarcus Overhagen
870a0795c6fSMarcus Overhagen// [e.moon 28sep99]
871a0795c6fSMarcus Overhagen// split group: given two nodes currently in the same group
872a0795c6fSMarcus Overhagen// that are not connected (directly OR indirectly),
873a0795c6fSMarcus Overhagen// this method removes outsideNode, and all nodes connected
874a0795c6fSMarcus Overhagen// to outsideNode, from the common group.  These nodes are
875a0795c6fSMarcus Overhagen// then added to a new group, returned in 'outGroup'.  The
876a0795c6fSMarcus Overhagen// new group has " split" appended to the end of the original
877a0795c6fSMarcus Overhagen// group's name.
878a0795c6fSMarcus Overhagen//
879a0795c6fSMarcus Overhagen// Returns B_NOT_ALLOWED if any of the above conditions aren't
880a0795c6fSMarcus Overhagen// met (ie. the nodes are in different groups or an indirect
881a0795c6fSMarcus Overhagen// route exists from one to the other), or B_OK if the group
882a0795c6fSMarcus Overhagen// was split successfully.
883a0795c6fSMarcus Overhagen
884a0795c6fSMarcus Overhagen
885a0795c6fSMarcus Overhagenclass _changeNodeGroupFn :
886a0795c6fSMarcus Overhagen	public	unary_function<NodeRef*, void> {
887a0795c6fSMarcus Overhagenpublic:
888a0795c6fSMarcus Overhagen	NodeGroup*										newGroup;
889d363440aSIngo Weinhold
890a0795c6fSMarcus Overhagen	_changeNodeGroupFn(
891a0795c6fSMarcus Overhagen		NodeGroup*									_newGroup) : newGroup(_newGroup) {
892a0795c6fSMarcus Overhagen		ASSERT(newGroup);
893a0795c6fSMarcus Overhagen	}
894d363440aSIngo Weinhold
895a0795c6fSMarcus Overhagen	void operator()(
896a0795c6fSMarcus Overhagen		NodeRef*										node) {
897a0795c6fSMarcus Overhagen
898a0795c6fSMarcus Overhagen		PRINT((
899a0795c6fSMarcus Overhagen			"_changeNodeGroupFn(): '%s'\n", node->name()));
900a0795c6fSMarcus Overhagen
901a0795c6fSMarcus Overhagen		status_t err;
902a0795c6fSMarcus Overhagen		NodeGroup* oldGroup = node->group();
903a0795c6fSMarcus Overhagen		if(oldGroup) {
904a0795c6fSMarcus Overhagen			err = oldGroup->removeNode(node);
905a0795c6fSMarcus Overhagen			ASSERT(err == B_OK);
906a0795c6fSMarcus Overhagen		}
907d363440aSIngo Weinhold
908a0795c6fSMarcus Overhagen		err = newGroup->addNode(node);
909a0795c6fSMarcus Overhagen		ASSERT(err == B_OK);
910a0795c6fSMarcus Overhagen	}
911a0795c6fSMarcus Overhagen};
912a0795c6fSMarcus Overhagen
913a0795c6fSMarcus Overhagenstatus_t NodeManager::splitGroup(
914a0795c6fSMarcus Overhagen	NodeRef*											insideNode,
915a0795c6fSMarcus Overhagen	NodeRef*											outsideNode,
916a0795c6fSMarcus Overhagen	NodeGroup**										outGroup) {
917a0795c6fSMarcus Overhagen
918a0795c6fSMarcus Overhagen	ASSERT(insideNode);
919a0795c6fSMarcus Overhagen	ASSERT(outsideNode);
920d363440aSIngo Weinhold
921a0795c6fSMarcus Overhagen	Autolock _l(this);
922a0795c6fSMarcus Overhagen
923a0795c6fSMarcus Overhagen	// ensure that no route exists from insideNode to outsideNode
924a0795c6fSMarcus Overhagen	if(findRoute(insideNode->id(), outsideNode->id())) {
925a0795c6fSMarcus Overhagen		PRINT((
9261a7bcf69SOliver Tappe			"!!! NodeManager::splitGroup(): route exists from %" B_PRId32
9271a7bcf69SOliver Tappe			" to %" B_PRId32 "\n", insideNode->id(), outsideNode->id()));
928a0795c6fSMarcus Overhagen		return B_NOT_ALLOWED;
929a0795c6fSMarcus Overhagen	}
930d363440aSIngo Weinhold
931a0795c6fSMarcus Overhagen	// make sure the nodes share a common group
932a0795c6fSMarcus Overhagen	NodeGroup* oldGroup = insideNode->group();
933a0795c6fSMarcus Overhagen	if(!oldGroup) {
9341bd15897SUrias McCullough		PRINT(("!!! NodeManager::splitGroup(): invalid group\n"));
935a0795c6fSMarcus Overhagen		return B_NOT_ALLOWED;
936a0795c6fSMarcus Overhagen	}
937a0795c6fSMarcus Overhagen	if(oldGroup != outsideNode->group()) {
938a0795c6fSMarcus Overhagen		PRINT((
9391a7bcf69SOliver Tappe			"!!! NodeManager::splitGroup(): mismatched groups for %" B_PRId32
9401a7bcf69SOliver Tappe			" and %" B_PRId32 "\n", insideNode->id(), outsideNode->id()));
941a0795c6fSMarcus Overhagen		return B_NOT_ALLOWED;
942a0795c6fSMarcus Overhagen	}
943a0795c6fSMarcus Overhagen
944a0795c6fSMarcus Overhagen	Autolock _l_old_group(oldGroup);
945a0795c6fSMarcus Overhagen
946a0795c6fSMarcus Overhagen	// create the new group
947a0795c6fSMarcus Overhagen	BString nameBuffer = oldGroup->name();
948a0795c6fSMarcus Overhagen	nameBuffer << " split";
949a0795c6fSMarcus Overhagen
950a0795c6fSMarcus Overhagen	NodeGroup* newGroup = createGroup(
951a0795c6fSMarcus Overhagen		nameBuffer.String(),
952a0795c6fSMarcus Overhagen		oldGroup->runMode());
953a0795c6fSMarcus Overhagen	*outGroup = newGroup;
954d363440aSIngo Weinhold
955a0795c6fSMarcus Overhagen	// move nodes connected to outsideNode from old to new group
956a0795c6fSMarcus Overhagen	_changeNodeGroupFn fn(newGroup);
957a0795c6fSMarcus Overhagen	fn(outsideNode);
958d363440aSIngo Weinhold
959a0795c6fSMarcus Overhagen	_for_each_state st;
960a0795c6fSMarcus Overhagen	_do_for_each_connected(
961a0795c6fSMarcus Overhagen		this,
962a0795c6fSMarcus Overhagen		outsideNode,
963a0795c6fSMarcus Overhagen		oldGroup,
964a0795c6fSMarcus Overhagen		true,
965a0795c6fSMarcus Overhagen		fn,
966a0795c6fSMarcus Overhagen		&st);
967d363440aSIngo Weinhold
968a0795c6fSMarcus Overhagen	// [e.moon 1dec99] a single-node group takes that node's name
969a0795c6fSMarcus Overhagen	if(newGroup->countNodes() == 1)
970a0795c6fSMarcus Overhagen		newGroup->setName(newGroup->nodeAt(0)->name());
971a0795c6fSMarcus Overhagen
972a0795c6fSMarcus Overhagen	if(oldGroup->countNodes() == 1)
973a0795c6fSMarcus Overhagen		oldGroup->setName(oldGroup->nodeAt(0)->name());
974a0795c6fSMarcus Overhagen
975a0795c6fSMarcus Overhagen	return B_OK;
976a0795c6fSMarcus Overhagen}
977a0795c6fSMarcus Overhagen
978a0795c6fSMarcus Overhagen
979a0795c6fSMarcus Overhagen// * INSTANTIATION & CONNECTION
980a0795c6fSMarcus Overhagen//   Use these calls rather than the associated BMediaRoster()
981a0795c6fSMarcus Overhagen//   methods to assure that the nodes and connections you set up
982a0795c6fSMarcus Overhagen//   can be properly serialized & reconstituted.
983a0795c6fSMarcus Overhagen
984a0795c6fSMarcus Overhagen// basic BMediaRoster::InstantiateDormantNode() wrapper
985d363440aSIngo Weinhold
986a0795c6fSMarcus Overhagenstatus_t NodeManager::instantiate(
987a0795c6fSMarcus Overhagen	const dormant_node_info&			info,
988a0795c6fSMarcus Overhagen	NodeRef**											outRef,
989a0795c6fSMarcus Overhagen	bigtime_t											timeout,
990a0795c6fSMarcus Overhagen	uint32												nodeFlags) {
991d363440aSIngo Weinhold
992a0795c6fSMarcus Overhagen	Autolock _l(this);
993a0795c6fSMarcus Overhagen	status_t err;
994a0795c6fSMarcus Overhagen	D_METHOD((
995a0795c6fSMarcus Overhagen		"NodeManager::instantiate()\n"));
996d363440aSIngo Weinhold
997a0795c6fSMarcus Overhagen	// * instantiate
998d363440aSIngo Weinhold
999a0795c6fSMarcus Overhagen	media_node node;
1000d363440aSIngo Weinhold
1001a0795c6fSMarcus Overhagen	if(m_useAddOnHost) {
1002a0795c6fSMarcus Overhagen		err = AddOnHost::InstantiateDormantNode(
1003a0795c6fSMarcus Overhagen			info, &node, timeout);
1004d363440aSIngo Weinhold
1005a0795c6fSMarcus Overhagen		if(err < B_OK) {
1006a0795c6fSMarcus Overhagen			node = media_node::null;
1007a0795c6fSMarcus Overhagen
1008a0795c6fSMarcus Overhagen			// attempt to relaunch
1009a0795c6fSMarcus Overhagen			BMessenger mess;
1010a0795c6fSMarcus Overhagen			err = AddOnHost::Launch(&mess);
1011a0795c6fSMarcus Overhagen			if(err < B_OK) {
1012a0795c6fSMarcus Overhagen				PRINT((
1013a0795c6fSMarcus Overhagen					"!!! NodeManager::instantiate(): giving up on AddOnHost\n"));
1014a0795c6fSMarcus Overhagen
1015a0795c6fSMarcus Overhagen				m_useAddOnHost = false;
1016a0795c6fSMarcus Overhagen			}
1017a0795c6fSMarcus Overhagen			else {
1018a0795c6fSMarcus Overhagen				err = AddOnHost::InstantiateDormantNode(
1019a0795c6fSMarcus Overhagen					info, &node, timeout);
1020a0795c6fSMarcus Overhagen			}
1021d363440aSIngo Weinhold		}
1022a0795c6fSMarcus Overhagen	}
1023d363440aSIngo Weinhold
1024a0795c6fSMarcus Overhagen	if(!m_useAddOnHost || node == media_node::null) {
1025a0795c6fSMarcus Overhagen		D_ROSTER((
1026a0795c6fSMarcus Overhagen			"# roster->InstantiateDormantNode()\n"));
1027a0795c6fSMarcus Overhagen		err = roster->InstantiateDormantNode(info, &node);
1028a0795c6fSMarcus Overhagen	}
1029d363440aSIngo Weinhold
1030a0795c6fSMarcus Overhagen	if(err < B_OK) {
1031a0795c6fSMarcus Overhagen		*outRef = 0;
1032a0795c6fSMarcus Overhagen		return err;
1033a0795c6fSMarcus Overhagen	}
1034a0795c6fSMarcus Overhagen
1035a0795c6fSMarcus Overhagen	if(node == media_node::null) {
1036a0795c6fSMarcus Overhagen		// [e.moon 23oct99] +++++
1037a0795c6fSMarcus Overhagen		// instantiating a soundcard input/output (emu10k or sonic_vibes)
1038a0795c6fSMarcus Overhagen		// produces a node ID of -1 (R4.5.2 x86)
1039a0795c6fSMarcus Overhagen		//
1040a0795c6fSMarcus Overhagen		PRINT((
1041a0795c6fSMarcus Overhagen			"! InstantiateDormantNode(): invalid media node\n"));
1042a0795c6fSMarcus Overhagen
1043a0795c6fSMarcus Overhagen		// bail out
1044a0795c6fSMarcus Overhagen		*outRef = 0;
1045a0795c6fSMarcus Overhagen		return B_BAD_INDEX;
1046a0795c6fSMarcus Overhagen	}
1047d363440aSIngo Weinhold
1048a0795c6fSMarcus Overhagen	// * create NodeRef
1049a0795c6fSMarcus Overhagen	NodeRef* ref = new NodeRef(
1050a0795c6fSMarcus Overhagen		node,
1051a0795c6fSMarcus Overhagen		this,
1052a0795c6fSMarcus Overhagen		nodeFlags, // | NodeRef::NO_ROSTER_WATCH, // +++++ e.moon 11oct99
1053a0795c6fSMarcus Overhagen		NodeRef::_INTERNAL);
1054a0795c6fSMarcus Overhagen
1055a0795c6fSMarcus Overhagen	ref->_setAddonHint(&info);
1056a0795c6fSMarcus Overhagen	_addRef(ref);
1057d363440aSIngo Weinhold
1058a0795c6fSMarcus Overhagen	// * return it
1059a0795c6fSMarcus Overhagen	*outRef = ref;
1060a0795c6fSMarcus Overhagen	return B_OK;
1061a0795c6fSMarcus Overhagen}
1062d363440aSIngo Weinhold
1063a0795c6fSMarcus Overhagen// SniffRef/Instantiate.../SetRefFor: a one-call interface
1064a0795c6fSMarcus Overhagen// to create a node capable of playing a given media file.
1065a0795c6fSMarcus Overhagen
1066a0795c6fSMarcus Overhagenstatus_t NodeManager::instantiate(
1067a0795c6fSMarcus Overhagen	const entry_ref&							file,
1068a0795c6fSMarcus Overhagen	uint64												requireNodeKinds,
1069a0795c6fSMarcus Overhagen	NodeRef**											outRef,
1070a0795c6fSMarcus Overhagen	bigtime_t											timeout,
1071a0795c6fSMarcus Overhagen	uint32												nodeFlags,
1072a0795c6fSMarcus Overhagen	bigtime_t*										outDuration) {
1073a0795c6fSMarcus Overhagen
1074a0795c6fSMarcus Overhagen	D_METHOD((
1075a0795c6fSMarcus Overhagen		"NodeManager::instantiate(ref)\n"));
1076a0795c6fSMarcus Overhagen
1077a0795c6fSMarcus Overhagen	// [no lock needed; calls the full form of instantiate()]
1078d363440aSIngo Weinhold
1079a0795c6fSMarcus Overhagen	status_t err;
1080d363440aSIngo Weinhold
1081a0795c6fSMarcus Overhagen	// * Find matching add-on
1082a0795c6fSMarcus Overhagen	dormant_node_info info;
10