xref: /haiku/src/servers/media/NodeManager.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2  * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files or portions
6  * thereof (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject
10  * to the following conditions:
11  *
12  *  * Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  *
15  *  * Redistributions in binary form must reproduce the above copyright notice
16  *    in the  binary, as well as this list of conditions and the following
17  *    disclaimer in the documentation and/or other materials provided with
18  *    the distribution.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  */
29 
30 
31 #include "NodeManager.h"
32 
33 #include <Autolock.h>
34 #include <Entry.h>
35 #include <MediaAddOn.h>
36 #include <MediaDefs.h>
37 #include <Message.h>
38 #include <Messenger.h>
39 #include <OS.h>
40 #include <Path.h>
41 
42 #include <debug.h>
43 #include <MediaMisc.h>
44 
45 #include "AppManager.h"
46 #include "DefaultManager.h"
47 #include "media_server.h"
48 
49 
50 const char*
51 get_node_type(node_type type)
52 {
53 #define CASE(c) case c: return #c;
54 	switch (type) {
55 		CASE(VIDEO_INPUT)
56 		CASE(AUDIO_INPUT)
57 		CASE(VIDEO_OUTPUT)
58 		CASE(AUDIO_MIXER)
59 		CASE(AUDIO_OUTPUT)
60 		CASE(AUDIO_OUTPUT_EX)
61 		CASE(TIME_SOURCE)
62 		CASE(SYSTEM_TIME_SOURCE)
63 
64 		default:
65 			return "unknown";
66 	}
67 #undef CASE
68 }
69 
70 
71 // #pragma mark -
72 
73 
74 NodeManager::NodeManager()
75 	:
76 	BLocker("node manager"),
77 	fNextAddOnID(1),
78 	fNextNodeID(1),
79 	fDefaultManager(new DefaultManager)
80 {
81 }
82 
83 
84 NodeManager::~NodeManager()
85 {
86 	delete fDefaultManager;
87 }
88 
89 
90 // #pragma mark - Default node management
91 
92 
93 status_t
94 NodeManager::SetDefaultNode(node_type type, const media_node* node,
95 	const dormant_node_info* info, const media_input* input)
96 {
97 	BAutolock _(this);
98 
99 	status_t status = B_BAD_VALUE;
100 	if (node != NULL)
101 		status = fDefaultManager->Set(node->node, NULL, 0, type);
102 	else if (input != NULL) {
103 		status = fDefaultManager->Set(input->node.node, input->name,
104 			input->destination.id, type);
105 	} else if (info != NULL) {
106 		media_node_id nodeID;
107 		int32 count = 1;
108 		status = GetInstances(info->addon, info->flavor_id, &nodeID, &count,
109 			count);
110 		if (status == B_OK)
111 			status = fDefaultManager->Set(nodeID, NULL, 0, type);
112 	}
113 
114 	if (status == B_OK && (type == VIDEO_INPUT || type == VIDEO_OUTPUT
115 			|| type == AUDIO_OUTPUT || type == AUDIO_INPUT)) {
116 		fDefaultManager->SaveState(this);
117 		Dump();
118 	}
119 	return status;
120 }
121 
122 
123 status_t
124 NodeManager::GetDefaultNode(node_type type, media_node_id* _nodeID,
125 	char* inputName, int32* _inputID)
126 {
127 	BAutolock _(this);
128 	return fDefaultManager->Get(_nodeID, inputName, _inputID, type);
129 }
130 
131 
132 status_t
133 NodeManager::RescanDefaultNodes()
134 {
135 	BAutolock _(this);
136 	return fDefaultManager->Rescan();
137 }
138 
139 
140 // #pragma mark - Live node management
141 
142 
143 status_t
144 NodeManager::RegisterNode(media_addon_id addOnID, int32 flavorID,
145 	const char* name, uint64 kinds, port_id port, team_id team,
146 	media_node_id* _nodeID)
147 {
148 	BAutolock _(this);
149 
150 	registered_node node;
151 	node.node_id = fNextNodeID;
152 	node.add_on_id = addOnID;
153 	node.flavor_id = flavorID;
154 	strlcpy(node.name, name, sizeof(node.name));
155 	node.kinds = kinds;
156 	node.port = port;
157 	node.containing_team = team;
158 	node.creator = -1; // will be set later
159 	node.ref_count = 1;
160 
161 	try {
162 		node.team_ref_count.insert(std::make_pair(team, 1));
163 
164 		fNodeMap.insert(std::make_pair(fNextNodeID, node));
165 	} catch (std::bad_alloc& exception) {
166 		return B_NO_MEMORY;
167 	}
168 
169 	*_nodeID = fNextNodeID++;
170 
171 	TRACE("NodeManager::RegisterNode: node %" B_PRId32 ", addon_id %" B_PRId32
172 		", flavor_id %" B_PRId32 ", name \"%s\", kinds %#Lx, port %" B_PRId32
173 		", team %" B_PRId32 "\n", *_nodeID, addOnID, flavorID, name, kinds,
174 		port, team);
175 	return B_OK;
176 }
177 
178 
179 status_t
180 NodeManager::UnregisterNode(media_node_id id, team_id team,
181 	media_addon_id* _addOnID, int32* _flavorID)
182 {
183 	TRACE("NodeManager::UnregisterNode enter: node %" B_PRId32 ", team %"
184 		B_PRId32 "\n", id, team);
185 
186 	BAutolock _(this);
187 
188 	NodeMap::iterator found = fNodeMap.find(id);
189 	if (found == fNodeMap.end()) {
190 		ERROR("NodeManager::UnregisterNode: couldn't find node %" B_PRId32
191 			" (team %" B_PRId32 ")\n", id, team);
192 		return B_ERROR;
193 	}
194 
195 	registered_node& node = found->second;
196 
197 	if (node.containing_team != team) {
198 		ERROR("NodeManager::UnregisterNode: team %" B_PRId32 " tried to "
199 			"unregister node %" B_PRId32 ", but it was instantiated by team %"
200 			B_PRId32 "\n", team, id, node.containing_team);
201 		return B_ERROR;
202 	}
203 	if (node.ref_count != 1) {
204 		ERROR("NodeManager::UnregisterNode: node %" B_PRId32 ", team %"
205 			B_PRId32 " has ref count %" B_PRId32 " (should be 1)\n", id, team,
206 			node.ref_count);
207 		//return B_ERROR;
208 	}
209 
210 	*_addOnID = node.add_on_id;
211 	*_flavorID = node.flavor_id;
212 
213 	fNodeMap.erase(found);
214 
215 	TRACE("NodeManager::UnregisterNode leave: node %" B_PRId32 ", addon_id %"
216 		B_PRId32 ", flavor_id %" B_PRId32 " team %" B_PRId32 "\n", id,
217 		*_addOnID, *_flavorID, team);
218 	return B_OK;
219 }
220 
221 
222 status_t
223 NodeManager::ReleaseNodeReference(media_node_id id, team_id team)
224 {
225 	TRACE("NodeManager::ReleaseNodeReference enter: node %" B_PRId32 ", team %"
226 		B_PRId32 "\n", id, team);
227 
228 	BAutolock _(this);
229 
230 	NodeMap::iterator found = fNodeMap.find(id);
231 	if (found == fNodeMap.end()) {
232 		ERROR("NodeManager::ReleaseNodeReference: node %" B_PRId32 " not "
233 			"found\n", id);
234 		return B_ERROR;
235 	}
236 
237 	registered_node& node = found->second;
238 
239 	TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
240 	if (teamRef == node.team_ref_count.end()) {
241 		// Normally it is an error to release a node in another team. But we
242 		// make one exception: if the node is global, and the creator team
243 		// tries to release it, we will release it in the the
244 		// media_addon_server.
245 		team_id addOnServer = gAppManager->AddOnServerTeam();
246 		teamRef = node.team_ref_count.find(addOnServer);
247 
248 		if (node.creator == team && teamRef != node.team_ref_count.end()) {
249 			PRINT(1, "!!! NodeManager::ReleaseNodeReference doing global "
250 				"release!\n");
251 			node.creator = -1; // invalidate!
252 			team = addOnServer;
253 		} else {
254 			ERROR("NodeManager::ReleaseNodeReference: node %" B_PRId32 " has "
255 				"no team %" B_PRId32 " references\n", id, team);
256 			return B_ERROR;
257 		}
258 	}
259 
260 #if DEBUG
261 	int32 teamCount = teamRef->second - 1;
262 	(void)teamCount;
263 #endif
264 
265 	if (--teamRef->second == 0)
266 		node.team_ref_count.erase(teamRef);
267 
268 	if (--node.ref_count == 0) {
269 		PRINT(1, "NodeManager::ReleaseNodeReference: detected released node is"
270 			" now unused, node %" B_PRId32 "\n", id);
271 
272 		// TODO: remove!
273 		node_final_release_command command;
274 		status_t status = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
275 			sizeof(command));
276 		if (status != B_OK) {
277 			ERROR("NodeManager::ReleaseNodeReference: can't send command to "
278 				"node %" B_PRId32 "\n", id);
279 			// ignore error
280 		}
281 	}
282 
283 	TRACE("NodeManager::ReleaseNodeReference leave: node %" B_PRId32 ", team %"
284 		B_PRId32 ", ref %" B_PRId32 ", team ref %" B_PRId32 "\n", id, team,
285 		node.ref_count, teamCount);
286 	return B_OK;
287 }
288 
289 
290 status_t
291 NodeManager::ReleaseNodeAll(media_node_id id)
292 {
293 	TRACE("NodeManager::ReleaseNodeAll enter: node %" B_PRId32 "\n", id);
294 
295 	BAutolock _(this);
296 
297 	NodeMap::iterator found = fNodeMap.find(id);
298 	if (found == fNodeMap.end()) {
299 		ERROR("NodeManager::ReleaseNodeAll: node %" B_PRId32 " not found\n",
300 			id);
301 		return B_ERROR;
302 	}
303 
304 	registered_node& node = found->second;
305 	node.team_ref_count.clear();
306 	node.ref_count = 0;
307 
308 	node_final_release_command command;
309 	status_t status = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
310 		sizeof(command));
311 	if (status != B_OK) {
312 		ERROR("NodeManager::ReleaseNodeAll: can't send command to "
313 			"node %" B_PRId32 "\n", id);
314 		// ignore error
315 	}
316 
317 	TRACE("NodeManager::ReleaseNodeAll leave: node %" B_PRId32 "\n", id);
318 	return B_OK;
319 }
320 
321 
322 status_t
323 NodeManager::SetNodeCreator(media_node_id id, team_id creator)
324 {
325 	TRACE("NodeManager::SetNodeCreator node %" B_PRId32 ", creator %" B_PRId32
326 		"\n", id, creator);
327 
328 	BAutolock _(this);
329 
330 	NodeMap::iterator found = fNodeMap.find(id);
331 	if (found == fNodeMap.end()) {
332 		ERROR("NodeManager::SetNodeCreator: node %" B_PRId32 " not found\n",
333 			id);
334 		return B_ERROR;
335 	}
336 
337 	registered_node& node = found->second;
338 
339 	if (node.creator != -1) {
340 		ERROR("NodeManager::SetNodeCreator: node %" B_PRId32 " is already"
341 			" assigned creator %" B_PRId32 "\n", id, node.creator);
342 		return B_ERROR;
343 	}
344 
345 	node.creator = creator;
346 	return B_OK;
347 }
348 
349 
350 status_t
351 NodeManager::GetCloneForID(media_node_id id, team_id team, media_node* node)
352 {
353 	TRACE("NodeManager::GetCloneForID enter: node %" B_PRId32 " team %"
354 		B_PRId32 "\n", id, team);
355 
356 	BAutolock _(this);
357 
358 	status_t status = _AcquireNodeReference(id, team);
359 	if (status != B_OK) {
360 		ERROR("NodeManager::GetCloneForID: couldn't increment ref count, "
361 			"node %" B_PRId32 " team %" B_PRId32 "\n", id, team);
362 		return status;
363 	}
364 
365 	NodeMap::iterator found = fNodeMap.find(id);
366 	if (found == fNodeMap.end()) {
367 		ERROR("NodeManager::GetCloneForID: node %" B_PRId32 " not found\n",
368 			id);
369 		return B_ERROR;
370 	}
371 
372 	registered_node& registeredNode = found->second;
373 
374 	node->node = registeredNode.node_id;
375 	node->port = registeredNode.port;
376 	node->kind = registeredNode.kinds;
377 
378 	TRACE("NodeManager::GetCloneForID leave: node %" B_PRId32 " team %"
379 		B_PRId32 "\n", id, team);
380 	return B_OK;
381 }
382 
383 
384 /*!	This function locates the default "node" for the requested "type" and
385 	returns a clone.
386 	If the requested type is AUDIO_OUTPUT_EX, also "input_name" and "input_id"
387 	need to be set and returned, as this is required by
388 	BMediaRoster::GetAudioOutput(media_node *out_node, int32 *out_input_id,
389 		BString *out_input_name).
390 */
391 status_t
392 NodeManager::GetClone(node_type type, team_id team, media_node* node,
393 	char* inputName, int32* _inputID)
394 {
395 	BAutolock _(this);
396 
397 	TRACE("NodeManager::GetClone enter: team %" B_PRId32 ", type %d (%s)\n",
398 		team, type, get_node_type(type));
399 
400 	media_node_id id;
401 	status_t status = GetDefaultNode(type, &id, inputName, _inputID);
402 	if (status != B_OK) {
403 		ERROR("NodeManager::GetClone: couldn't GetDefaultNode, team %" B_PRId32
404 			", type %d (%s)\n", team, type, get_node_type(type));
405 		*node = media_node::null;
406 		return status;
407 	}
408 	ASSERT(id > 0);
409 
410 	status = GetCloneForID(id, team, node);
411 	if (status != B_OK) {
412 		ERROR("NodeManager::GetClone: couldn't GetCloneForID, id %" B_PRId32
413 			", team %" B_PRId32 ", type %d (%s)\n", id, team, type,
414 			get_node_type(type));
415 		*node = media_node::null;
416 		return status;
417 	}
418 	ASSERT(id == node->node);
419 
420 	TRACE("NodeManager::GetClone leave: node id %" B_PRId32 ", node port %"
421 		B_PRId32 ", node kind %#lx\n", node->node, node->port, node->kind);
422 	return B_OK;
423 }
424 
425 
426 status_t
427 NodeManager::ReleaseNode(const media_node& node, team_id team)
428 {
429 	TRACE("NodeManager::ReleaseNode enter: node %" B_PRId32 " team %" B_PRId32
430 		"\n", node.node, team);
431 
432 	if (ReleaseNodeReference(node.node, team) != B_OK) {
433 		ERROR("NodeManager::ReleaseNode: couldn't decrement node %" B_PRId32
434 			" team %" B_PRId32 " ref count\n", node.node, team);
435 	}
436 
437 	return B_OK;
438 }
439 
440 
441 status_t
442 NodeManager::PublishInputs(const media_node& node, const media_input* inputs,
443 	int32 count)
444 {
445 	BAutolock _(this);
446 
447 	NodeMap::iterator found = fNodeMap.find(node.node);
448 	if (found == fNodeMap.end()) {
449 		ERROR("NodeManager::PublishInputs: node %" B_PRId32 " not found\n",
450 			node.node);
451 		return B_ERROR;
452 	}
453 
454 	registered_node& registeredNode = found->second;
455 
456 	registeredNode.input_list.clear();
457 
458 	try {
459 		for (int32 i = 0; i < count; i++)
460 			registeredNode.input_list.push_back(inputs[i]);
461 	} catch (std::bad_alloc& exception) {
462 		return B_NO_MEMORY;
463 	}
464 
465 	return B_OK;
466 }
467 
468 
469 status_t
470 NodeManager::PublishOutputs(const media_node &node, const media_output* outputs,
471 	int32 count)
472 {
473 	BAutolock _(this);
474 
475 	NodeMap::iterator found = fNodeMap.find(node.node);
476 	if (found == fNodeMap.end()) {
477 		ERROR("NodeManager::PublishOutputs: node %" B_PRId32 " not found\n",
478 			node.node);
479 		return B_ERROR;
480 	}
481 
482 	registered_node& registeredNode = found->second;
483 
484 	registeredNode.output_list.clear();
485 
486 	try {
487 		for (int32 i = 0; i < count; i++)
488 			registeredNode.output_list.push_back(outputs[i]);
489 	} catch (std::bad_alloc& exception) {
490 		return B_NO_MEMORY;
491 	}
492 
493 	return B_OK;
494 }
495 
496 
497 status_t
498 NodeManager::FindNodeID(port_id port, media_node_id* _id)
499 {
500 	BAutolock _(this);
501 
502 	NodeMap::iterator iterator = fNodeMap.begin();
503 	for (; iterator != fNodeMap.end(); iterator++) {
504 		registered_node& node = iterator->second;
505 
506 		if (node.port == port) {
507 			*_id = node.node_id;
508 			TRACE("NodeManager::FindNodeID found port %" B_PRId32 ", node %"
509 				B_PRId32 "\n", port, node.node_id);
510 			return B_OK;
511 		}
512 
513 		OutputList::iterator outIterator = node.output_list.begin();
514 		for (; outIterator != node.output_list.end(); outIterator++) {
515 			if (outIterator->source.port == port) {
516 				*_id = node.node_id;
517 				TRACE("NodeManager::FindNodeID found output port %" B_PRId32
518 					", node %" B_PRId32 "\n", port, node.node_id);
519 				return B_OK;
520 			}
521 		}
522 
523 		InputList::iterator inIterator = node.input_list.begin();
524 		for (; inIterator != node.input_list.end(); inIterator++) {
525 			if (inIterator->destination.port == port) {
526 				*_id = node.node_id;
527 				TRACE("NodeManager::FindNodeID found input port %" B_PRId32
528 					", node %" B_PRId32 "\n", port, node.node_id);
529 				return B_OK;
530 			}
531 		}
532 	}
533 
534 	ERROR("NodeManager::FindNodeID failed, port %" B_PRId32 "\n", port);
535 	return B_ERROR;
536 }
537 
538 
539 status_t
540 NodeManager::GetDormantNodeInfo(const media_node& node,
541 	dormant_node_info* nodeInfo)
542 {
543 	// TODO: not sure if this is correct
544 	BAutolock _(this);
545 
546 	NodeMap::iterator found = fNodeMap.find(node.node);
547 	if (found == fNodeMap.end()) {
548 		ERROR("NodeManager::GetDormantNodeInfo: node %" B_PRId32 " not found"
549 			"\n", node.node);
550 		return B_ERROR;
551 	}
552 
553 	registered_node& registeredNode = found->second;
554 
555 	if (registeredNode.add_on_id == -1
556 		&& node.node != NODE_SYSTEM_TIMESOURCE_ID) {
557 		// This function must return an error if the node is application owned
558 		TRACE("NodeManager::GetDormantNodeInfo NODE IS APPLICATION OWNED! "
559 			"node %" B_PRId32 ", add_on_id %" B_PRId32 ", flavor_id %" B_PRId32
560 			", name \"%s\"\n", node.node, registeredNode.add_on_id,
561 			registeredNode.flavor_id, registeredNode.name);
562 		return B_ERROR;
563 	}
564 
565 	ASSERT(node.port == registeredNode.port);
566 	ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
567 		== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
568 
569 	nodeInfo->addon = registeredNode.add_on_id;
570 	nodeInfo->flavor_id = registeredNode.flavor_id;
571 	strlcpy(nodeInfo->name, registeredNode.name, sizeof(nodeInfo->name));
572 
573 	TRACE("NodeManager::GetDormantNodeInfo node %" B_PRId32 ", add_on_id %"
574 		B_PRId32 ", flavor_id %" B_PRId32 ", name \"%s\"\n", node.node,
575 		registeredNode.add_on_id, registeredNode.flavor_id,
576 		registeredNode.name);
577 	return B_OK;
578 }
579 
580 
581 status_t
582 NodeManager::GetLiveNodeInfo(const media_node& node, live_node_info* liveInfo)
583 {
584 	BAutolock _(this);
585 
586 	NodeMap::iterator found = fNodeMap.find(node.node);
587 	if (found == fNodeMap.end()) {
588 		ERROR("NodeManager::GetLiveNodeInfo: node %" B_PRId32 " not found\n",
589 			node.node);
590 		return B_ERROR;
591 	}
592 
593 	registered_node& registeredNode = found->second;
594 
595 	ASSERT(node.port == registeredNode.port);
596 	ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
597 		== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
598 
599 	liveInfo->node = node;
600 	liveInfo->hint_point = BPoint(0, 0);
601 	strlcpy(liveInfo->name, registeredNode.name, sizeof(liveInfo->name));
602 
603 	TRACE("NodeManager::GetLiveNodeInfo node %" B_PRId32 ", name = \"%s\"\n",
604 		node.node, registeredNode.name);
605 	return B_OK;
606 }
607 
608 
609 status_t
610 NodeManager::GetInstances(media_addon_id addOnID, int32 flavorID,
611 	media_node_id* ids, int32* _count, int32 maxCount)
612 {
613 	BAutolock _(this);
614 
615 	NodeMap::iterator iterator = fNodeMap.begin();
616 	int32 count = 0;
617 	for (; iterator != fNodeMap.end() && count < maxCount; iterator++) {
618 		registered_node& node = iterator->second;
619 
620 		if (node.add_on_id == addOnID && node.flavor_id == flavorID)
621 			ids[count++] = node.node_id;
622 	}
623 
624 	TRACE("NodeManager::GetInstances found %" B_PRId32 " instances for "
625 		"addon_id %" B_PRId32 ", flavor_id %" B_PRId32 "\n", count, addOnID,
626 		flavorID);
627 	*_count = count;
628 	return B_OK;
629 }
630 
631 
632 status_t
633 NodeManager::GetLiveNodes(LiveNodeList& liveNodes, int32 maxCount,
634 	const media_format* inputFormat, const media_format* outputFormat,
635 	const char* name, uint64 requireKinds)
636 {
637 	TRACE("NodeManager::GetLiveNodes: maxCount %" B_PRId32 ", in-format %p, "
638 		"out-format %p, name %s, require kinds 0x%" B_PRIx64 "\n", maxCount,
639 		inputFormat, outputFormat, name != NULL ? name : "NULL", requireKinds);
640 
641 	BAutolock _(this);
642 
643 	// Determine the count of byte to compare when checking for a name with
644 	// or without wildcard
645 	size_t nameLength = 0;
646 	if (name != NULL) {
647 		nameLength = strlen(name);
648 		if (nameLength > 0 && name[nameLength - 1] == '*')
649 			nameLength--;
650 	}
651 
652 	NodeMap::iterator iterator = fNodeMap.begin();
653 	int32 count = 0;
654 	for (; iterator != fNodeMap.end() && count < maxCount; iterator++) {
655 		registered_node& node = iterator->second;
656 
657 		if ((node.kinds & requireKinds) != requireKinds)
658 			continue;
659 
660 		if (nameLength != 0) {
661 			if (strncmp(name, node.name, nameLength) != 0)
662 				continue;
663 		}
664 
665 		if (inputFormat != NULL) {
666 			bool found = false;
667 
668 			for (InputList::iterator inIterator = node.input_list.begin();
669 					inIterator != node.input_list.end(); inIterator++) {
670 				media_input& input = *inIterator;
671 
672 				if (format_is_compatible(*inputFormat, input.format)) {
673 					found = true;
674 					break;
675 				}
676 			}
677 
678 			if (!found)
679 				continue;
680 		}
681 
682 		if (outputFormat != NULL) {
683 			bool found = false;
684 
685 			for (OutputList::iterator outIterator = node.output_list.begin();
686 					outIterator != node.output_list.end(); outIterator++) {
687 				media_output& output = *outIterator;
688 
689 				if (format_is_compatible(*outputFormat, output.format)) {
690 					found = true;
691 					break;
692 				}
693 			}
694 
695 			if (!found)
696 				continue;
697 		}
698 
699 		live_node_info info;
700 		info.node.node = node.node_id;
701 		info.node.port = node.port;
702 		info.node.kind = node.kinds;
703 		info.hint_point = BPoint(0, 0);
704 		strlcpy(info.name, node.name, sizeof(info.name));
705 
706 		try {
707 			liveNodes.push_back(info);
708 		} catch (std::bad_alloc& exception) {
709 			return B_NO_MEMORY;
710 		}
711 
712 		count++;
713 	}
714 
715 	TRACE("NodeManager::GetLiveNodes found %" B_PRId32 "\n", count);
716 	return B_OK;
717 }
718 
719 
720 /*!	Add media_node_id of all live nodes to the message
721 	int32 "media_node_id" (multiple items)
722 */
723 status_t
724 NodeManager::GetLiveNodes(BMessage* message)
725 {
726 	BAutolock _(this);
727 
728 	NodeMap::iterator iterator = fNodeMap.begin();
729 	for (; iterator != fNodeMap.end(); iterator++) {
730 		registered_node& node = iterator->second;
731 
732 		if (message->AddInt32("media_node_id", node.node_id) != B_OK)
733 			return B_NO_MEMORY;
734 	}
735 
736 	return B_OK;
737 }
738 
739 
740 // #pragma mark - Registration of BMediaAddOns
741 
742 
743 void
744 NodeManager::RegisterAddOn(const entry_ref& ref, media_addon_id* _newID)
745 {
746 	BAutolock _(this);
747 
748 	media_addon_id id = fNextAddOnID++;
749 
750 //	printf("NodeManager::RegisterAddOn: ref-name \"%s\", assigning id %"
751 //		B_PRId32 "\n", ref.name, id);
752 
753 	try {
754 		fPathMap.insert(std::make_pair(id, ref));
755 		*_newID = id;
756 	} catch (std::bad_alloc& exception) {
757 		*_newID = -1;
758 	}
759 }
760 
761 
762 void
763 NodeManager::UnregisterAddOn(media_addon_id addOnID)
764 {
765 	PRINT(1, "NodeManager::UnregisterAddOn: id %" B_PRId32 "\n", addOnID);
766 
767 	BAutolock _(this);
768 
769 	RemoveDormantFlavorInfo(addOnID);
770 	fPathMap.erase(addOnID);
771 }
772 
773 
774 status_t
775 NodeManager::GetAddOnRef(media_addon_id addOnID, entry_ref* ref)
776 {
777 	BAutolock _(this);
778 
779 	PathMap::iterator found = fPathMap.find(addOnID);
780 	if (found == fPathMap.end())
781 		return B_ERROR;
782 
783 	*ref = found->second;
784 	return B_OK;
785 }
786 
787 
788 // #pragma mark - Registration of node flavors, published by BMediaAddOns
789 
790 
791 //!	This function is only used (indirectly) by the media_addon_server.
792 status_t
793 NodeManager::AddDormantFlavorInfo(const dormant_flavor_info& flavorInfo)
794 {
795 	PRINT(1, "NodeManager::AddDormantFlavorInfo, addon-id %" B_PRId32 ", "
796 		"flavor-id %" B_PRId32 ", name \"%s\", flavor-name \"%s\", flavor-info"
797 		" \"%s\"\n", flavorInfo.node_info.addon,
798 		flavorInfo.node_info.flavor_id, flavorInfo.node_info.name,
799 		flavorInfo.name, flavorInfo.info);
800 
801 	BAutolock _(this);
802 
803 	// Try to find the addon-id/flavor-id in the list.
804 	// If it already exists, update the info, but don't change its instance
805 	// count.
806 
807 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
808 			iterator != fDormantFlavors.end(); iterator++) {
809 		dormant_add_on_flavor_info& info = *iterator;
810 
811 		if (info.add_on_id != flavorInfo.node_info.addon
812 			|| info.flavor_id != flavorInfo.node_info.flavor_id)
813 			continue;
814 
815 		if (info.info_valid) {
816 			ERROR("NodeManager::AddDormantFlavorInfo, addon-id %" B_PRId32 ", "
817 				"flavor-id %" B_PRId32 " does already exist\n",
818 				info.info.node_info.addon, info.info.node_info.flavor_id);
819 		}
820 
821 		TRACE("NodeManager::AddDormantFlavorInfo, updating addon-id %" B_PRId32
822 			", flavor-id %" B_PRId32 "\n", info.info.node_info.addon,
823 			info.info.node_info.flavor_id);
824 
825 		info.max_instances_count = flavorInfo.possible_count > 0
826 			? flavorInfo.possible_count : INT32_MAX;
827 		info.info_valid = true;
828 		info.info = flavorInfo;
829 		return B_OK;
830 	}
831 
832 	// Insert information into the list
833 
834 	dormant_add_on_flavor_info info;
835 	info.add_on_id = flavorInfo.node_info.addon;
836 	info.flavor_id = flavorInfo.node_info.flavor_id;
837 	info.max_instances_count = flavorInfo.possible_count > 0
838 		? flavorInfo.possible_count : INT32_MAX;
839 	info.instances_count = 0;
840 	info.info_valid = true;
841 	info.info = flavorInfo;
842 
843 	try {
844 		fDormantFlavors.push_back(info);
845 	} catch (std::bad_alloc& exception) {
846 		return B_NO_MEMORY;
847 	}
848 
849 	return B_OK;
850 }
851 
852 
853 //!	This function is only used (indirectly) by the media_addon_server
854 void
855 NodeManager::InvalidateDormantFlavorInfo(media_addon_id addOnID)
856 {
857 	BAutolock _(this);
858 
859 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
860 			iterator != fDormantFlavors.end(); iterator++) {
861 		dormant_add_on_flavor_info& info = *iterator;
862 
863 		if (info.add_on_id == addOnID && info.info_valid) {
864 			PRINT(1, "NodeManager::InvalidateDormantFlavorInfo, addon-id %"
865 				B_PRId32 ", flavor-id %" B_PRId32 ", name \"%s\", flavor-name "
866 				"\"%s\", flavor-info \"%s\"\n", info.info.node_info.addon,
867 				info.info.node_info.flavor_id, info.info.node_info.name,
868 				info.info.name, info.info.info);
869 
870 			info.info_valid = false;
871 		}
872 	}
873 }
874 
875 
876 //!	This function is only used (indirectly) by the media_addon_server
877 void
878 NodeManager::RemoveDormantFlavorInfo(media_addon_id addOnID)
879 {
880 	BAutolock _(this);
881 
882 	for (size_t index = 0; index < fDormantFlavors.size(); index++) {
883 		dormant_add_on_flavor_info& info = fDormantFlavors[index];
884 
885 		if (info.add_on_id == addOnID) {
886 			PRINT(1, "NodeManager::RemoveDormantFlavorInfo, addon-id %"
887 				B_PRId32 ", flavor-id %" B_PRId32 ", name \"%s\", flavor-name "
888 				"\"%s\", flavor-info \"%s\"\n", info.info.node_info.addon,
889 				info.info.node_info.flavor_id, info.info.node_info.name,
890 				info.info.name, info.info.info);
891 			fDormantFlavors.erase(fDormantFlavors.begin() + index--);
892 		}
893 	}
894 }
895 
896 
897 status_t
898 NodeManager::IncrementFlavorInstancesCount(media_addon_id addOnID,
899 	int32 flavorID, team_id team)
900 {
901 	BAutolock _(this);
902 
903 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
904 			iterator != fDormantFlavors.end(); iterator++) {
905 		dormant_add_on_flavor_info& info = *iterator;
906 
907 		if (info.add_on_id != addOnID || info.flavor_id != flavorID)
908 			continue;
909 
910 		if (info.instances_count >= info.max_instances_count) {
911 			// maximum (or more) instances already exist
912 			ERROR("NodeManager::IncrementFlavorInstancesCount addon-id %"
913 				B_PRId32 ", flavor-id %" B_PRId32 " maximum (or more) "
914 				"instances already exist\n", addOnID, flavorID);
915 			return B_ERROR;
916 		}
917 
918 		TeamCountMap::iterator teamInstance
919 			= info.team_instances_count.find(team);
920 		if (teamInstance == info.team_instances_count.end()) {
921 			// This is the team's first instance
922 			try {
923 				info.team_instances_count.insert(std::make_pair(team, 1));
924 			} catch (std::bad_alloc& exception) {
925 				return B_NO_MEMORY;
926 			}
927 		} else {
928 			// Just increase its ref count
929 			teamInstance->second++;
930 		}
931 
932 		info.instances_count++;
933 		return B_OK;
934 	}
935 
936 	ERROR("NodeManager::IncrementFlavorInstancesCount addon-id %" B_PRId32 ", "
937 		"flavor-id %" B_PRId32 " not found\n", addOnID, flavorID);
938 	return B_ERROR;
939 }
940 
941 
942 status_t
943 NodeManager::DecrementFlavorInstancesCount(media_addon_id addOnID,
944 	int32 flavorID, team_id team)
945 {
946 	BAutolock _(this);
947 
948 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
949 			iterator != fDormantFlavors.end(); iterator++) {
950 		dormant_add_on_flavor_info& info = *iterator;
951 
952 		if (info.add_on_id != addOnID || info.flavor_id != flavorID)
953 			continue;
954 
955 		TeamCountMap::iterator teamInstance
956 			= info.team_instances_count.find(team);
957 		if (teamInstance == info.team_instances_count.end()) {
958 			ERROR("NodeManager::DecrementFlavorInstancesCount addon-id %"
959 				B_PRId32 ", flavor-id %" B_PRId32 " team %" B_PRId32 " has no "
960 				"references\n", addOnID, flavorID, team);
961 			return B_ERROR;
962 		}
963 		if (--teamInstance->second == 0)
964 			info.team_instances_count.erase(teamInstance);
965 
966 		info.instances_count--;
967 		return B_OK;
968 	}
969 
970 	ERROR("NodeManager::DecrementFlavorInstancesCount addon-id %" B_PRId32 ", "
971 		"flavor-id %" B_PRId32 " not found\n", addOnID, flavorID);
972 	return B_ERROR;
973 }
974 
975 
976 //!	This function is called when the media_addon_server has crashed
977 void
978 NodeManager::CleanupDormantFlavorInfos()
979 {
980 	PRINT(1, "NodeManager::CleanupDormantFlavorInfos\n");
981 
982 	BAutolock _(this);
983 	fDormantFlavors.clear();
984 	// TODO: FlavorsChanged() notification
985 
986 	PRINT(1, "NodeManager::CleanupDormantFlavorInfos done\n");
987 }
988 
989 
990 status_t
991 NodeManager::GetDormantNodes(dormant_node_info* infos, int32* _count,
992 	const media_format* input, const media_format* output, const char* name,
993 	uint64 requireKinds, uint64 denyKinds)
994 {
995 	BAutolock _(this);
996 
997 	// Determine the count of byte to compare when checking for a name with
998 	// or without wildcard
999 	size_t nameLength = 0;
1000 	if (name != NULL) {
1001 		nameLength = strlen(name);
1002 		if (nameLength > 0 && name[nameLength - 1] == '*')
1003 			nameLength--;
1004 	}
1005 
1006 	int32 maxCount = *_count;
1007 	int32 count = 0;
1008 
1009 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1010 			iterator != fDormantFlavors.end() && count < maxCount; iterator++) {
1011 		dormant_add_on_flavor_info& info = *iterator;
1012 
1013 		if (!info.info_valid)
1014 			continue;
1015 
1016 		if ((info.info.kinds & requireKinds) != requireKinds
1017 			|| (info.info.kinds & denyKinds) != 0)
1018 			continue;
1019 
1020 		if (nameLength != 0) {
1021 			if (strncmp(name, info.info.name, nameLength) != 0)
1022 				continue;
1023 		}
1024 
1025 		if (input != NULL) {
1026 			bool found = false;
1027 
1028 			for (int32 i = 0; i < info.info.in_format_count; i++) {
1029 				if (format_is_compatible(*input, info.info.in_formats[i])) {
1030 					found = true;
1031 					break;
1032 				}
1033 			}
1034 
1035 			if (!found)
1036 				continue;
1037 		}
1038 
1039 		if (output != NULL) {
1040 			bool found = false;
1041 
1042 			for (int32 i = 0; i < info.info.out_format_count; i++) {
1043 				if (format_is_compatible(*output, info.info.out_formats[i])) {
1044 					found = true;
1045 					break;
1046 				}
1047 			}
1048 
1049 			if (!found)
1050 				continue;
1051 		}
1052 
1053 		infos[count++] = info.info.node_info;
1054 	}
1055 
1056 	*_count = count;
1057 	return B_OK;
1058 }
1059 
1060 
1061 status_t
1062 NodeManager::GetDormantFlavorInfoFor(media_addon_id addOnID, int32 flavorID,
1063 	dormant_flavor_info* flavorInfo)
1064 {
1065 	BAutolock _(this);
1066 
1067 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1068 			iterator != fDormantFlavors.end(); iterator++) {
1069 		dormant_add_on_flavor_info& info = *iterator;
1070 
1071 		if (info.add_on_id == addOnID && info.flavor_id == flavorID
1072 			&& info.info_valid) {
1073 			*flavorInfo = info.info;
1074 			return B_OK;
1075 		}
1076 	}
1077 
1078 	return B_ERROR;
1079 }
1080 
1081 
1082 // #pragma mark - Misc.
1083 
1084 
1085 void
1086 NodeManager::CleanupTeam(team_id team)
1087 {
1088 	BAutolock _(this);
1089 
1090 	fDefaultManager->CleanupTeam(team);
1091 
1092 	PRINT(1, "NodeManager::CleanupTeam: team %" B_PRId32 "\n", team);
1093 
1094 	// TODO: send notifications after removing nodes
1095 
1096 	// Cleanup node references
1097 
1098 	for (NodeMap::iterator iterator = fNodeMap.begin();
1099 			iterator != fNodeMap.end();) {
1100 		registered_node& node = iterator->second;
1101 		NodeMap::iterator remove = iterator++;
1102 
1103 		// If the gone team was the creator of some global dormant node
1104 		// instance, we now invalidate that we may want to remove that
1105 		// global node, but I'm not sure
1106 		if (node.creator == team) {
1107 			node.creator = -1;
1108 			// fall through
1109 		}
1110 
1111 		// If the team hosting this node is gone, remove node from database
1112 		if (node.containing_team == team) {
1113 			PRINT(1, "NodeManager::CleanupTeam: removing node id %" B_PRId32
1114 				", team %" B_PRId32 "\n", node.node_id, team);
1115 			fNodeMap.erase(remove);
1116 			continue;
1117 		}
1118 
1119 		// Check the list of teams that have references to this node, and
1120 		// remove the team
1121 		TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
1122 		if (teamRef != node.team_ref_count.end()) {
1123 			PRINT(1, "NodeManager::CleanupTeam: removing %" B_PRId32 " refs "
1124 				"from node id %" B_PRId32 ", team %" B_PRId32 "\n",
1125 				teamRef->second, node.node_id, team);
1126 			node.ref_count -= teamRef->second;
1127 			if (node.ref_count == 0) {
1128 				PRINT(1, "NodeManager::CleanupTeam: removing node id %"
1129 					B_PRId32 " that has no teams\n", node.node_id);
1130 
1131 				fNodeMap.erase(remove);
1132 			} else
1133 				node.team_ref_count.erase(teamRef);
1134 		}
1135 	}
1136 
1137 	// Cleanup add-on references
1138 
1139 	for (size_t index = 0; index < fDormantFlavors.size(); index++) {
1140 		dormant_add_on_flavor_info& flavorInfo = fDormantFlavors[index];
1141 
1142 		TeamCountMap::iterator instanceCount
1143 			= flavorInfo.team_instances_count.find(team);
1144 		if (instanceCount != flavorInfo.team_instances_count.end()) {
1145 			PRINT(1, "NodeManager::CleanupTeam: removing %" B_PRId32 " "
1146 				"instances from addon %" B_PRId32 ", flavor %" B_PRId32 "\n",
1147 				instanceCount->second, flavorInfo.add_on_id,
1148 				flavorInfo.flavor_id);
1149 
1150 			flavorInfo.instances_count -= instanceCount->second;
1151 			if (flavorInfo.instances_count <= 0)
1152 				fDormantFlavors.erase(fDormantFlavors.begin() + index--);
1153 			else
1154 				flavorInfo.team_instances_count.erase(team);
1155 		}
1156 	}
1157 }
1158 
1159 
1160 status_t
1161 NodeManager::LoadState()
1162 {
1163 	BAutolock _(this);
1164 	return fDefaultManager->LoadState();
1165 }
1166 
1167 status_t
1168 NodeManager::SaveState()
1169 {
1170 	BAutolock _(this);
1171 	return fDefaultManager->SaveState(this);
1172 }
1173 
1174 
1175 void
1176 NodeManager::Dump()
1177 {
1178 	BAutolock _(this);
1179 
1180 	// for each addon-id, the add-on path map contains an entry_ref
1181 
1182 	printf("\nNodeManager: addon path map follows:\n");
1183 
1184 	for (PathMap::iterator iterator = fPathMap.begin();
1185 			iterator != fPathMap.end(); iterator++) {
1186 		BPath path(&iterator->second);
1187 		printf(" addon-id %" B_PRId32 ", path \"%s\"\n", iterator->first,
1188 			path.InitCheck() == B_OK ? path.Path() : "INVALID");
1189 	}
1190 
1191 	printf("NodeManager: list end\n\n");
1192 
1193 	// for each node-id, the registered node map contians information about
1194 	// source of the node, users, etc.
1195 
1196 	printf("NodeManager: registered nodes map follows:\n");
1197 	for (NodeMap::iterator iterator = fNodeMap.begin();
1198 			iterator != fNodeMap.end(); iterator++) {
1199 		registered_node& node = iterator->second;
1200 
1201 		printf("  node-id %" B_PRId32 ", addon-id %" B_PRId32 ", addon-flavor-"
1202 			"id %" B_PRId32 ", port %" B_PRId32 ", creator %" B_PRId32 ", "
1203 			"team %" B_PRId32 ", kinds %#08" B_PRIx64 ", name \"%s\", "
1204 			"ref_count %" B_PRId32 "\n", node.node_id, node.add_on_id,
1205 			node.flavor_id, node.port, node.creator, node.containing_team,
1206 			node.kinds, node.name, node.ref_count);
1207 
1208 		printf("    teams (refcount): ");
1209 		for (TeamCountMap::iterator refsIterator = node.team_ref_count.begin();
1210 				refsIterator != node.team_ref_count.end(); refsIterator++) {
1211 			printf("%" B_PRId32 " (%" B_PRId32 "), ", refsIterator->first,
1212 				refsIterator->second);
1213 		}
1214 		printf("\n");
1215 
1216 		for (InputList::iterator inIterator = node.input_list.begin();
1217 				inIterator != node.input_list.end(); inIterator++) {
1218 			media_input& input = *inIterator;
1219 			printf("    media_input: node-id %" B_PRId32 ", node-port %"
1220 				B_PRId32 ", source-port %" B_PRId32 ", source-id  %" B_PRId32
1221 				", dest-port %" B_PRId32 ", dest-id %" B_PRId32 ", name "
1222 				"\"%s\"\n", input.node.node, input.node.port, input.source.port,
1223 				input.source.id, input.destination.port, input.destination.id,
1224 				input.name);
1225 		}
1226 		if (node.input_list.empty())
1227 			printf("    media_input: none\n");
1228 
1229 		for (OutputList::iterator outIterator = node.output_list.begin();
1230 				outIterator != node.output_list.end(); outIterator++) {
1231 			media_output& output = *outIterator;
1232 			printf("    media_output: node-id %" B_PRId32 ", node-port %"
1233 				B_PRId32 ", source-port %" B_PRId32 ", source-id  %" B_PRId32
1234 				", dest-port %" B_PRId32 ", dest-id %" B_PRId32 ", name "
1235 				"\"%s\"\n", output.node.node, output.node.port,
1236 				output.source.port, output.source.id, output.destination.port,
1237 				output.destination.id, output.name);
1238 		}
1239 		if (node.output_list.empty())
1240 			printf("    media_output: none\n");
1241 	}
1242 
1243 	printf("NodeManager: list end\n");
1244 	printf("\n");
1245 
1246 	// Dormant add-on flavors
1247 
1248 	printf("NodeManager: dormant flavor list follows:\n");
1249 
1250 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1251 			iterator != fDormantFlavors.end(); iterator++) {
1252 		dormant_add_on_flavor_info& flavorInfo = *iterator;
1253 
1254 		printf("  addon-id %" B_PRId32 ", flavor-id %" B_PRId32 ", max "
1255 			"instances count %" B_PRId32 ", instances count %" B_PRId32 ", "
1256 			"info valid %s\n", flavorInfo.add_on_id, flavorInfo.flavor_id,
1257 			flavorInfo.max_instances_count, flavorInfo.instances_count,
1258 			flavorInfo.info_valid ? "yes" : "no");
1259 		printf("    teams (instances): ");
1260 		for (TeamCountMap::iterator countIterator
1261 					= flavorInfo.team_instances_count.begin();
1262 				countIterator != flavorInfo.team_instances_count.end();
1263 				countIterator++) {
1264 			printf("%" B_PRId32 " (%" B_PRId32 "), ", countIterator->first,
1265 				countIterator->second);
1266 		}
1267 		printf("\n");
1268 		if (!flavorInfo.info_valid)
1269 			continue;
1270 
1271 		printf("    addon-id %" B_PRId32 ", addon-flavor-id %" B_PRId32 ", "
1272 			"addon-name \"%s\"\n", flavorInfo.info.node_info.addon,
1273 			flavorInfo.info.node_info.flavor_id,
1274 			flavorInfo.info.node_info.name);
1275 		printf("    flavor-kinds %#08" B_PRIx64 ", flavor_flags %#08" B_PRIx32
1276 			", internal_id %" B_PRId32 ", possible_count %" B_PRId32 ", "
1277 			"in_format_count %" B_PRId32 ", out_format_count %" B_PRId32 "\n",
1278 			flavorInfo.info.kinds, flavorInfo.info.flavor_flags,
1279 			flavorInfo.info.internal_id, flavorInfo.info.possible_count,
1280 			flavorInfo.info.in_format_count, flavorInfo.info.out_format_count);
1281 		printf("    flavor-name \"%s\"\n", flavorInfo.info.name);
1282 		printf("    flavor-info \"%s\"\n", flavorInfo.info.info);
1283 	}
1284 	printf("NodeManager: list end\n");
1285 
1286 	fDefaultManager->Dump();
1287 }
1288 
1289 
1290 // #pragma mark - private methods
1291 
1292 
1293 status_t
1294 NodeManager::_AcquireNodeReference(media_node_id id, team_id team)
1295 {
1296 	TRACE("NodeManager::_AcquireNodeReference enter: node %" B_PRId32 ", team "
1297 		"%" B_PRId32 "\n", id, team);
1298 
1299 	BAutolock _(this);
1300 
1301 	NodeMap::iterator found = fNodeMap.find(id);
1302 	if (found == fNodeMap.end()) {
1303 		ERROR("NodeManager::_AcquireNodeReference: node %" B_PRId32 " not "
1304 			"found\n", id);
1305 		return B_ERROR;
1306 	}
1307 
1308 	registered_node& node = found->second;
1309 
1310 	TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
1311 	if (teamRef == node.team_ref_count.end()) {
1312 		// This is the team's first reference
1313 		try {
1314 			node.team_ref_count.insert(std::make_pair(team, 1));
1315 		} catch (std::bad_alloc& exception) {
1316 			return B_NO_MEMORY;
1317 		}
1318 	} else {
1319 		// Just increase its ref count
1320 		teamRef->second++;
1321 	}
1322 
1323 	node.ref_count++;
1324 
1325 	TRACE("NodeManager::_AcquireNodeReference leave: node %" B_PRId32 ", team "
1326 		"%" B_PRId32 ", ref %" B_PRId32 ", team ref %" B_PRId32 "\n", id, team,
1327 		node.ref_count, node.team_ref_count.find(team)->second);
1328 	return B_OK;
1329 }
1330