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