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