1255a01c7Sbeveloper/*
27bcdb362SDario Casalinuovo * Copyright (c) 2015 Dario Casalinuovo
3255a01c7Sbeveloper * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
4255a01c7Sbeveloper *
5255a01c7Sbeveloper * Permission is hereby granted, free of charge, to any person obtaining
6255a01c7Sbeveloper * a copy of this software and associated documentation files or portions
7255a01c7Sbeveloper * thereof (the "Software"), to deal in the Software without restriction,
8255a01c7Sbeveloper * including without limitation the rights to use, copy, modify, merge,
9255a01c7Sbeveloper * publish, distribute, sublicense, and/or sell copies of the Software,
10255a01c7Sbeveloper * and to permit persons to whom the Software is furnished to do so, subject
11255a01c7Sbeveloper * to the following conditions:
12255a01c7Sbeveloper *
13255a01c7Sbeveloper *  * Redistributions of source code must retain the above copyright notice,
14255a01c7Sbeveloper *    this list of conditions and the following disclaimer.
15255a01c7Sbeveloper *
16255a01c7Sbeveloper *  * Redistributions in binary form must reproduce the above copyright notice
17255a01c7Sbeveloper *    in the  binary, as well as this list of conditions and the following
18255a01c7Sbeveloper *    disclaimer in the documentation and/or other materials provided with
19255a01c7Sbeveloper *    the distribution.
20255a01c7Sbeveloper *
21255a01c7Sbeveloper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22255a01c7Sbeveloper * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23255a01c7Sbeveloper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24255a01c7Sbeveloper * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25255a01c7Sbeveloper * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26255a01c7Sbeveloper * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27255a01c7Sbeveloper * THE SOFTWARE.
28255a01c7Sbeveloper *
291299bfb2Sbeveloper */
30255a01c7Sbeveloper
319c3b4706SAxel Dörfler
329c3b4706SAxel Dörfler#include "NodeManager.h"
339c3b4706SAxel Dörfler
347bcdb362SDario Casalinuovo#include <Application.h>
359c3b4706SAxel Dörfler#include <Autolock.h>
36d6b71edfSbeveloper#include <Entry.h>
379c3b4706SAxel Dörfler#include <MediaAddOn.h>
389c3b4706SAxel Dörfler#include <MediaDefs.h>
3952a38012Sejakowatz#include <Message.h>
4052a38012Sejakowatz#include <Messenger.h>
419c3b4706SAxel Dörfler#include <OS.h>
429c3b4706SAxel Dörfler#include <Path.h>
439c3b4706SAxel Dörfler
448f3a6845SBarrett#include <MediaDebug.h>
459c3b4706SAxel Dörfler#include <MediaMisc.h>
46d97447baSDario Casalinuovo#include <Notifications.h>
479c3b4706SAxel Dörfler
4854187cc6Sbeveloper#include "AppManager.h"
499c3b4706SAxel Dörfler#include "DefaultManager.h"
509c3b4706SAxel Dörfler#include "media_server.h"
5154187cc6Sbeveloper
5252a38012Sejakowatz
539c3b4706SAxel Dörflerconst char*
549c3b4706SAxel Dörflerget_node_type(node_type type)
559c3b4706SAxel Dörfler{
569c3b4706SAxel Dörfler#define CASE(c) case c: return #c;
579c3b4706SAxel Dörfler	switch (type) {
589c3b4706SAxel Dörfler		CASE(VIDEO_INPUT)
599c3b4706SAxel Dörfler		CASE(AUDIO_INPUT)
609c3b4706SAxel Dörfler		CASE(VIDEO_OUTPUT)
619c3b4706SAxel Dörfler		CASE(AUDIO_MIXER)
629c3b4706SAxel Dörfler		CASE(AUDIO_OUTPUT)
639c3b4706SAxel Dörfler		CASE(AUDIO_OUTPUT_EX)
649c3b4706SAxel Dörfler		CASE(TIME_SOURCE)
659c3b4706SAxel Dörfler		CASE(SYSTEM_TIME_SOURCE)
669c3b4706SAxel Dörfler
679c3b4706SAxel Dörfler		default:
689c3b4706SAxel Dörfler			return "unknown";
699c3b4706SAxel Dörfler	}
709c3b4706SAxel Dörfler#undef CASE
719c3b4706SAxel Dörfler}
729c3b4706SAxel Dörfler
739c3b4706SAxel Dörfler
749c3b4706SAxel Dörfler// #pragma mark -
759c3b4706SAxel Dörfler
762df68a7bSbeveloper
779c3b4706SAxel DörflerNodeManager::NodeManager()
789c3b4706SAxel Dörfler	:
799c3b4706SAxel Dörfler	BLocker("node manager"),
80cf4e2277Sbeveloper	fNextAddOnID(1),
81cf4e2277Sbeveloper	fNextNodeID(1),
82cf4e2277Sbeveloper	fDefaultManager(new DefaultManager)
8352a38012Sejakowatz{
8452a38012Sejakowatz}
8552a38012Sejakowatz
861299bfb2Sbeveloper
8752a38012SejakowatzNodeManager::~NodeManager()
8852a38012Sejakowatz{
892df68a7bSbeveloper	delete fDefaultManager;
9052a38012Sejakowatz}
9152a38012Sejakowatz
929c3b4706SAxel Dörfler
939c3b4706SAxel Dörfler// #pragma mark - Default node management
949c3b4706SAxel Dörfler
95d9b7ae21Sbeveloper
96d9b7ae21Sbeveloperstatus_t
979c3b4706SAxel DörflerNodeManager::SetDefaultNode(node_type type, const media_node* node,
989c3b4706SAxel Dörfler	const dormant_node_info* info, const media_input* input)
99d9b7ae21Sbeveloper{
1009c3b4706SAxel Dörfler	BAutolock _(this);
1019c3b4706SAxel Dörfler
1029c3b4706SAxel Dörfler	status_t status = B_BAD_VALUE;
1039c3b4706SAxel Dörfler	if (node != NULL)
1049c3b4706SAxel Dörfler		status = fDefaultManager->Set(node->node, NULL, 0, type);
1059c3b4706SAxel Dörfler	else if (input != NULL) {
1069c3b4706SAxel Dörfler		status = fDefaultManager->Set(input->node.node, input->name,
1079c3b4706SAxel Dörfler			input->destination.id, type);
1089c3b4706SAxel Dörfler	} else if (info != NULL) {
1099c3b4706SAxel Dörfler		media_node_id nodeID;
1109c3b4706SAxel Dörfler		int32 count = 1;
1119c3b4706SAxel Dörfler		status = GetInstances(info->addon, info->flavor_id, &nodeID, &count,
1129c3b4706SAxel Dörfler			count);
1139c3b4706SAxel Dörfler		if (status == B_OK)
1149c3b4706SAxel Dörfler			status = fDefaultManager->Set(nodeID, NULL, 0, type);
1159c3b4706SAxel Dörfler	}
1169c3b4706SAxel Dörfler
1179c3b4706SAxel Dörfler	if (status == B_OK && (type == VIDEO_INPUT || type == VIDEO_OUTPUT
1189c3b4706SAxel Dörfler			|| type == AUDIO_OUTPUT || type == AUDIO_INPUT)) {
1199c3b4706SAxel Dörfler		fDefaultManager->SaveState(this);
1209c3b4706SAxel Dörfler		Dump();
1219c3b4706SAxel Dörfler	}
1229c3b4706SAxel Dörfler	return status;
123d9b7ae21Sbeveloper}
124d9b7ae21Sbeveloper
125d9b7ae21Sbeveloper
126d9b7ae21Sbeveloperstatus_t
1279c3b4706SAxel DörflerNodeManager::GetDefaultNode(node_type type, media_node_id* _nodeID,
1289c3b4706SAxel Dörfler	char* inputName, int32* _inputID)
129d9b7ae21Sbeveloper{
1309c3b4706SAxel Dörfler	BAutolock _(this);
1319c3b4706SAxel Dörfler	return fDefaultManager->Get(_nodeID, inputName, _inputID, type);
1329c3b4706SAxel Dörfler}
1339c3b4706SAxel Dörfler
1349c3b4706SAxel Dörfler
1359c3b4706SAxel Dörflerstatus_t
1369c3b4706SAxel DörflerNodeManager::RescanDefaultNodes()
1379c3b4706SAxel Dörfler{
1389c3b4706SAxel Dörfler	BAutolock _(this);
1399c3b4706SAxel Dörfler	return fDefaultManager->Rescan();
1409c3b4706SAxel Dörfler}
1419c3b4706SAxel Dörfler
1429c3b4706SAxel Dörfler
1439c3b4706SAxel Dörfler// #pragma mark - Live node management
1449c3b4706SAxel Dörfler
1459c3b4706SAxel Dörfler
1469c3b4706SAxel Dörflerstatus_t
1479c3b4706SAxel DörflerNodeManager::RegisterNode(media_addon_id addOnID, int32 flavorID,
1489c3b4706SAxel Dörfler	const char* name, uint64 kinds, port_id port, team_id team,
1497bcdb362SDario Casalinuovo	media_node_id timesource, media_node_id* _nodeID)
1509c3b4706SAxel Dörfler{
1519c3b4706SAxel Dörfler	BAutolock _(this);
1529c3b4706SAxel Dörfler
1539c3b4706SAxel Dörfler	registered_node node;
1547bcdb362SDario Casalinuovo	node.timesource_id = timesource;
1559c3b4706SAxel Dörfler	node.add_on_id = addOnID;
1569c3b4706SAxel Dörfler	node.flavor_id = flavorID;
1579c3b4706SAxel Dörfler	strlcpy(node.name, name, sizeof(node.name));
1589c3b4706SAxel Dörfler	node.kinds = kinds;
1599c3b4706SAxel Dörfler	node.port = port;
1609c3b4706SAxel Dörfler	node.containing_team = team;
1619c3b4706SAxel Dörfler	node.creator = -1; // will be set later
1629c3b4706SAxel Dörfler	node.ref_count = 1;
1639c3b4706SAxel Dörfler
16477c6944cSDario Casalinuovo	if ((node.kinds & B_TIME_SOURCE) != 0
165cb80fc94SDario Casalinuovo			&& strcmp(node.name, "System clock") == 0) {
166cb80fc94SDario Casalinuovo		// This may happen when media_addon_server crash,
167cb80fc94SDario Casalinuovo		// we will replace the old timesource.
168cb80fc94SDario Casalinuovo		node.node_id = NODE_SYSTEM_TIMESOURCE_ID;
169cb80fc94SDario Casalinuovo
170cb80fc94SDario Casalinuovo		NodeMap::iterator found = fNodeMap.find(node.node_id);
171cb80fc94SDario Casalinuovo		if (found != fNodeMap.end())
172cb80fc94SDario Casalinuovo			fNodeMap.erase(node.node_id);
173cb80fc94SDario Casalinuovo
174cb80fc94SDario Casalinuovo		*_nodeID = node.node_id;
175cb80fc94SDario Casalinuovo	} else {
176cb80fc94SDario Casalinuovo		node.node_id = fNextNodeID;
177cb80fc94SDario Casalinuovo		*_nodeID = node.node_id;
178cb80fc94SDario Casalinuovo	}
179cb80fc94SDario Casalinuovo
1809c3b4706SAxel Dörfler	try {
1819c3b4706SAxel Dörfler		node.team_ref_count.insert(std::make_pair(team, 1));
182cb80fc94SDario Casalinuovo		fNodeMap.insert(std::make_pair(node.node_id, node));
1839c3b4706SAxel Dörfler	} catch (std::bad_alloc& exception) {
1849c3b4706SAxel Dörfler		return B_NO_MEMORY;
1851299bfb2Sbeveloper	}
1869c3b4706SAxel Dörfler
187cb80fc94SDario Casalinuovo	fNextNodeID++;
1889c3b4706SAxel Dörfler
189fe1f74abSJérôme Duval	TRACE("NodeManager::RegisterNode: node %" B_PRId32 ", addon_id %" B_PRId32
190fe1f74abSJérôme Duval		", flavor_id %" B_PRId32 ", name \"%s\", kinds %#Lx, port %" B_PRId32
191fe1f74abSJérôme Duval		", team %" B_PRId32 "\n", *_nodeID, addOnID, flavorID, name, kinds,
192fe1f74abSJérôme Duval		port, team);
1931299bfb2Sbeveloper	return B_OK;
1941299bfb2Sbeveloper}
1951299bfb2Sbeveloper
1961299bfb2Sbeveloper
1971299bfb2Sbeveloperstatus_t
1989c3b4706SAxel DörflerNodeManager::UnregisterNode(media_node_id id, team_id team,
1999c3b4706SAxel Dörfler	media_addon_id* _addOnID, int32* _flavorID)
2001299bfb2Sbeveloper{
201fe1f74abSJérôme Duval	TRACE("NodeManager::UnregisterNode enter: node %" B_PRId32 ", team %"
202fe1f74abSJérôme Duval		B_PRId32 "\n", id, team);
2039c3b4706SAxel Dörfler
2049c3b4706SAxel Dörfler	BAutolock _(this);
2059c3b4706SAxel Dörfler
2069c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(id);
2079c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
208fe1f74abSJérôme Duval		ERROR("NodeManager::UnregisterNode: couldn't find node %" B_PRId32
209fe1f74abSJérôme Duval			" (team %" B_PRId32 ")\n", id, team);
2101299bfb2Sbeveloper		return B_ERROR;
2111299bfb2Sbeveloper	}
2129c3b4706SAxel Dörfler
2139c3b4706SAxel Dörfler	registered_node& node = found->second;
2149c3b4706SAxel Dörfler
2159c3b4706SAxel Dörfler	if (node.containing_team != team) {
216fe1f74abSJérôme Duval		ERROR("NodeManager::UnregisterNode: team %" B_PRId32 " tried to "
217fe1f74abSJérôme Duval			"unregister node %" B_PRId32 ", but it was instantiated by team %"
218fe1f74abSJérôme Duval			B_PRId32 "\n", team, id, node.containing_team);
2199c3b4706SAxel Dörfler		return B_ERROR;
2201299bfb2Sbeveloper	}
2219c3b4706SAxel Dörfler	if (node.ref_count != 1) {
222fe1f74abSJérôme Duval		ERROR("NodeManager::UnregisterNode: node %" B_PRId32 ", team %"
223fe1f74abSJérôme Duval			B_PRId32 " has ref count %" B_PRId32 " (should be 1)\n", id, team,
224fe1f74abSJérôme Duval			node.ref_count);
2259c3b4706SAxel Dörfler		//return B_ERROR;
2269c3b4706SAxel Dörfler	}
2279c3b4706SAxel Dörfler
228cb80fc94SDario Casalinuovo	if (_addOnID != NULL)
229cb80fc94SDario Casalinuovo		*_addOnID = node.add_on_id;
230cb80fc94SDario Casalinuovo
231cb80fc94SDario Casalinuovo	if (_flavorID != NULL)
232cb80fc94SDario Casalinuovo		*_flavorID = node.flavor_id;
2339c3b4706SAxel Dörfler
2349c3b4706SAxel Dörfler	fNodeMap.erase(found);
2359c3b4706SAxel Dörfler
236fe1f74abSJérôme Duval	TRACE("NodeManager::UnregisterNode leave: node %" B_PRId32 ", addon_id %"
237fe1f74abSJérôme Duval		B_PRId32 ", flavor_id %" B_PRId32 " team %" B_PRId32 "\n", id,
238fe1f74abSJérôme Duval		*_addOnID, *_flavorID, team);
2391299bfb2Sbeveloper	return B_OK;
2401299bfb2Sbeveloper}
2411299bfb2Sbeveloper
2421299bfb2Sbeveloper
2431299bfb2Sbeveloperstatus_t
2449c3b4706SAxel DörflerNodeManager::ReleaseNodeReference(media_node_id id, team_id team)
2451299bfb2Sbeveloper{
246fe1f74abSJérôme Duval	TRACE("NodeManager::ReleaseNodeReference enter: node %" B_PRId32 ", team %"
247fe1f74abSJérôme Duval		B_PRId32 "\n", id, team);
2489c3b4706SAxel Dörfler
2499c3b4706SAxel Dörfler	BAutolock _(this);
2509c3b4706SAxel Dörfler
2519c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(id);
2529c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
253fe1f74abSJérôme Duval		ERROR("NodeManager::ReleaseNodeReference: node %" B_PRId32 " not "
254fe1f74abSJérôme Duval			"found\n", id);
2551299bfb2Sbeveloper		return B_ERROR;
2561299bfb2Sbeveloper	}
2579c3b4706SAxel Dörfler
2589c3b4706SAxel Dörfler	registered_node& node = found->second;
2599c3b4706SAxel Dörfler
2609c3b4706SAxel Dörfler	TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
2619c3b4706SAxel Dörfler	if (teamRef == node.team_ref_count.end()) {
2629c3b4706SAxel Dörfler		// Normally it is an error to release a node in another team. But we
2639c3b4706SAxel Dörfler		// make one exception: if the node is global, and the creator team
2649c3b4706SAxel Dörfler		// tries to release it, we will release it in the the
2659c3b4706SAxel Dörfler		// media_addon_server.
2669c3b4706SAxel Dörfler		team_id addOnServer = gAppManager->AddOnServerTeam();
2679c3b4706SAxel Dörfler		teamRef = node.team_ref_count.find(addOnServer);
2689c3b4706SAxel Dörfler
2699c3b4706SAxel Dörfler		if (node.creator == team && teamRef != node.team_ref_count.end()) {
2709c3b4706SAxel Dörfler			PRINT(1, "!!! NodeManager::ReleaseNodeReference doing global "
2719c3b4706SAxel Dörfler				"release!\n");
2729c3b4706SAxel Dörfler			node.creator = -1; // invalidate!
2739c3b4706SAxel Dörfler			team = addOnServer;
27454187cc6Sbeveloper		} else {
275fe1f74abSJérôme Duval			ERROR("NodeManager::ReleaseNodeReference: node %" B_PRId32 " has "
276fe1f74abSJérôme Duval				"no team %" B_PRId32 " references\n", id, team);
27754187cc6Sbeveloper			return B_ERROR;
27854187cc6Sbeveloper		}
2791299bfb2Sbeveloper	}
2809dec2310SAxel Dörfler
2819c3b4706SAxel Dörfler#if DEBUG
2829c3b4706SAxel Dörfler	int32 teamCount = teamRef->second - 1;
28391d01236SMichael Lotz	(void)teamCount;
2849c3b4706SAxel Dörfler#endif
2859c3b4706SAxel Dörfler
2869c3b4706SAxel Dörfler	if (--teamRef->second == 0)
2879c3b4706SAxel Dörfler		node.team_ref_count.erase(teamRef);
2889c3b4706SAxel Dörfler
2899c3b4706SAxel Dörfler	if (--node.ref_count == 0) {
290fe1f74abSJérôme Duval		PRINT(1, "NodeManager::ReleaseNodeReference: detected released node is"
291fe1f74abSJérôme Duval			" now unused, node %" B_PRId32 "\n", id);
2929c3b4706SAxel Dörfler
2939c3b4706SAxel Dörfler		// TODO: remove!
2949c3b4706SAxel Dörfler		node_final_release_command command;
2959c3b4706SAxel Dörfler		status_t status = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
2969c3b4706SAxel Dörfler			sizeof(command));
2979c3b4706SAxel Dörfler		if (status != B_OK) {
2989c3b4706SAxel Dörfler			ERROR("NodeManager::ReleaseNodeReference: can't send command to "
299fe1f74abSJérôme Duval				"node %" B_PRId32 "\n", id);
3009c3b4706SAxel Dörfler			// ignore error
3019c3b4706SAxel Dörfler		}
302cf4e2277Sbeveloper	}
3039dec2310SAxel Dörfler
304fe1f74abSJérôme Duval	TRACE("NodeManager::ReleaseNodeReference leave: node %" B_PRId32 ", team %"
305fe1f74abSJérôme Duval		B_PRId32 ", ref %" B_PRId32 ", team ref %" B_PRId32 "\n", id, team,
306fe1f74abSJérôme Duval		node.ref_count, teamCount);
307d9b7ae21Sbeveloper	return B_OK;
308d9b7ae21Sbeveloper}
309d9b7ae21Sbeveloper
3109c3b4706SAxel Dörfler
3116aee58a4SJérôme Duvalstatus_t
3126aee58a4SJérôme DuvalNodeManager::ReleaseNodeAll(media_node_id id)
3136aee58a4SJérôme Duval{
314fe1f74abSJérôme Duval	TRACE("NodeManager::ReleaseNodeAll enter: node %" B_PRId32 "\n", id);
3156aee58a4SJérôme Duval
3166aee58a4SJérôme Duval	BAutolock _(this);
3176aee58a4SJérôme Duval
3186aee58a4SJérôme Duval	NodeMap::iterator found = fNodeMap.find(id);
3196aee58a4SJérôme Duval	if (found == fNodeMap.end()) {
320fe1f74abSJérôme Duval		ERROR("NodeManager::ReleaseNodeAll: node %" B_PRId32 " not found\n",
321fe1f74abSJérôme Duval			id);
3226aee58a4SJérôme Duval		return B_ERROR;
3236aee58a4SJérôme Duval	}
3246aee58a4SJérôme Duval
3256aee58a4SJérôme Duval	registered_node& node = found->second;
3266aee58a4SJérôme Duval	node.team_ref_count.clear();
3276aee58a4SJérôme Duval	node.ref_count = 0;
3286aee58a4SJérôme Duval
3296aee58a4SJérôme Duval	node_final_release_command command;
3306aee58a4SJérôme Duval	status_t status = SendToPort(node.port, NODE_FINAL_RELEASE, &command,
3316aee58a4SJérôme Duval		sizeof(command));
3326aee58a4SJérôme Duval	if (status != B_OK) {
3336aee58a4SJérôme Duval		ERROR("NodeManager::ReleaseNodeAll: can't send command to "
334fe1f74abSJérôme Duval			"node %" B_PRId32 "\n", id);
3356aee58a4SJérôme Duval		// ignore error
3366aee58a4SJérôme Duval	}
3376aee58a4SJérôme Duval
338fe1f74abSJérôme Duval	TRACE("NodeManager::ReleaseNodeAll leave: node %" B_PRId32 "\n", id);
3396aee58a4SJérôme Duval	return B_OK;
3406aee58a4SJérôme Duval}
3416aee58a4SJérôme Duval
3426aee58a4SJérôme Duval
34354187cc6Sbeveloperstatus_t
3449c3b4706SAxel DörflerNodeManager::SetNodeCreator(media_node_id id, team_id creator)
34554187cc6Sbeveloper{
346fe1f74abSJérôme Duval	TRACE("NodeManager::SetNodeCreator node %" B_PRId32 ", creator %" B_PRId32
347fe1f74abSJérôme Duval		"\n", id, creator);
34854187cc6Sbeveloper
3499c3b4706SAxel Dörfler	BAutolock _(this);
35054187cc6Sbeveloper
3519c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(id);
3529c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
353fe1f74abSJérôme Duval		ERROR("NodeManager::SetNodeCreator: node %" B_PRId32 " not found\n",
354fe1f74abSJérôme Duval			id);
35554187cc6Sbeveloper		return B_ERROR;
35654187cc6Sbeveloper	}
3579dec2310SAxel Dörfler
3589c3b4706SAxel Dörfler	registered_node& node = found->second;
3599c3b4706SAxel Dörfler
3609c3b4706SAxel Dörfler	if (node.creator != -1) {
361fe1f74abSJérôme Duval		ERROR("NodeManager::SetNodeCreator: node %" B_PRId32 " is already"
362fe1f74abSJérôme Duval			" assigned creator %" B_PRId32 "\n", id, node.creator);
36354187cc6Sbeveloper		return B_ERROR;
36454187cc6Sbeveloper	}
3659dec2310SAxel Dörfler
3669c3b4706SAxel Dörfler	node.creator = creator;
36754187cc6Sbeveloper	return B_OK;
36854187cc6Sbeveloper}
369d9b7ae21Sbeveloper
370cf4e2277Sbeveloper
371d9b7ae21Sbeveloperstatus_t
3729c3b4706SAxel DörflerNodeManager::GetCloneForID(media_node_id id, team_id team, media_node* node)
373d9b7ae21Sbeveloper{
374fe1f74abSJérôme Duval	TRACE("NodeManager::GetCloneForID enter: node %" B_PRId32 " team %"
375fe1f74abSJérôme Duval		B_PRId32 "\n", id, team);
3761299bfb2Sbeveloper
3779c3b4706SAxel Dörfler	BAutolock _(this);
3789c3b4706SAxel Dörfler
3799c3b4706SAxel Dörfler	status_t status = _AcquireNodeReference(id, team);
3809c3b4706SAxel Dörfler	if (status != B_OK) {
3819dec2310SAxel Dörfler		ERROR("NodeManager::GetCloneForID: couldn't increment ref count, "
382fe1f74abSJérôme Duval			"node %" B_PRId32 " team %" B_PRId32 "\n", id, team);
3839c3b4706SAxel Dörfler		return status;
3841299bfb2Sbeveloper	}
3851299bfb2Sbeveloper
3869c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(id);
3879c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
388fe1f74abSJérôme Duval		ERROR("NodeManager::GetCloneForID: node %" B_PRId32 " not found\n",
389fe1f74abSJérôme Duval			id);
3901299bfb2Sbeveloper		return B_ERROR;
3911299bfb2Sbeveloper	}
3921299bfb2Sbeveloper
3939c3b4706SAxel Dörfler	registered_node& registeredNode = found->second;
3941299bfb2Sbeveloper
3959c3b4706SAxel Dörfler	node->node = registeredNode.node_id;
3969c3b4706SAxel Dörfler	node->port = registeredNode.port;
3979c3b4706SAxel Dörfler	node->kind = registeredNode.kinds;
3989c3b4706SAxel Dörfler
399fe1f74abSJérôme Duval	TRACE("NodeManager::GetCloneForID leave: node %" B_PRId32 " team %"
400fe1f74abSJérôme Duval		B_PRId32 "\n", id, team);
401d9b7ae21Sbeveloper	return B_OK;
402d9b7ae21Sbeveloper}
403d9b7ae21Sbeveloper
404d9b7ae21Sbeveloper
4059dec2310SAxel Dörfler/*!	This function locates the default "node" for the requested "type" and
4069dec2310SAxel Dörfler	returns a clone.
4079dec2310SAxel Dörfler	If the requested type is AUDIO_OUTPUT_EX, also "input_name" and "input_id"
4089dec2310SAxel Dörfler	need to be set and returned, as this is required by
4099dec2310SAxel Dörfler	BMediaRoster::GetAudioOutput(media_node *out_node, int32 *out_input_id,
4109dec2310SAxel Dörfler		BString *out_input_name).
4119dec2310SAxel Dörfler*/
412d9b7ae21Sbeveloperstatus_t
4139c3b4706SAxel DörflerNodeManager::GetClone(node_type type, team_id team, media_node* node,
4149c3b4706SAxel Dörfler	char* inputName, int32* _inputID)
415d9b7ae21Sbeveloper{
4169c3b4706SAxel Dörfler	BAutolock _(this);
4172df68a7bSbeveloper
418fe1f74abSJérôme Duval	TRACE("NodeManager::GetClone enter: team %" B_PRId32 ", type %d (%s)\n",
419fe1f74abSJérôme Duval		team, type, get_node_type(type));
4209dec2310SAxel Dörfler
4219c3b4706SAxel Dörfler	media_node_id id;
4229c3b4706SAxel Dörfler	status_t status = GetDefaultNode(type, &id, inputName, _inputID);
4232df68a7bSbeveloper	if (status != B_OK) {
424fe1f74abSJérôme Duval		ERROR("NodeManager::GetClone: couldn't GetDefaultNode, team %" B_PRId32
425fe1f74abSJérôme Duval			", type %d (%s)\n", team, type, get_node_type(type));
4262df68a7bSbeveloper		*node = media_node::null;
4272df68a7bSbeveloper		return status;
4282df68a7bSbeveloper	}
4292df68a7bSbeveloper	ASSERT(id > 0);
4302df68a7bSbeveloper
4319c3b4706SAxel Dörfler	status = GetCloneForID(id, team, node);
4322df68a7bSbeveloper	if (status != B_OK) {
433fe1f74abSJérôme Duval		ERROR("NodeManager::GetClone: couldn't GetCloneForID, id %" B_PRId32
434fe1f74abSJérôme Duval			", team %" B_PRId32 ", type %d (%s)\n", id, team, type,
435fe1f74abSJérôme Duval			get_node_type(type));
4362df68a7bSbeveloper		*node = media_node::null;
4372df68a7bSbeveloper		return status;
4382df68a7bSbeveloper	}
4392df68a7bSbeveloper	ASSERT(id == node->node);
4402df68a7bSbeveloper
441fe1f74abSJérôme Duval	TRACE("NodeManager::GetClone leave: node id %" B_PRId32 ", node port %"
442fe1f74abSJérôme Duval		B_PRId32 ", node kind %#lx\n", node->node, node->port, node->kind);
4432df68a7bSbeveloper	return B_OK;
444d9b7ae21Sbeveloper}
445d9b7ae21Sbeveloper
446d9b7ae21Sbeveloper
447d9b7ae21Sbeveloperstatus_t
4489c3b4706SAxel DörflerNodeManager::ReleaseNode(const media_node& node, team_id team)
449d9b7ae21Sbeveloper{
450fe1f74abSJérôme Duval	TRACE("NodeManager::ReleaseNode enter: node %" B_PRId32 " team %" B_PRId32
451fe1f74abSJérôme Duval		"\n", node.node, team);
4529c3b4706SAxel Dörfler
4539c3b4706SAxel Dörfler	if (ReleaseNodeReference(node.node, team) != B_OK) {
454fe1f74abSJérôme Duval		ERROR("NodeManager::ReleaseNode: couldn't decrement node %" B_PRId32
455fe1f74abSJérôme Duval			" team %" B_PRId32 " ref count\n", node.node, team);
4561299bfb2Sbeveloper	}
4579c3b4706SAxel Dörfler
458d9b7ae21Sbeveloper	return B_OK;
459d9b7ae21Sbeveloper}
460d9b7ae21Sbeveloper
461d9b7ae21Sbeveloper
462d9b7ae21Sbeveloperstatus_t
4639c3b4706SAxel DörflerNodeManager::PublishInputs(const media_node& node, const media_input* inputs,
4649c3b4706SAxel Dörfler	int32 count)
465d9b7ae21Sbeveloper{
4669c3b4706SAxel Dörfler	BAutolock _(this);
4679c3b4706SAxel Dörfler
4689c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(node.node);
4699c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
470fe1f74abSJérôme Duval		ERROR("NodeManager::PublishInputs: node %" B_PRId32 " not found\n",
471fe1f74abSJérôme Duval			node.node);
4721299bfb2Sbeveloper		return B_ERROR;
4731299bfb2Sbeveloper	}
4749c3b4706SAxel Dörfler
4759c3b4706SAxel Dörfler	registered_node& registeredNode = found->second;
4769c3b4706SAxel Dörfler
4779c3b4706SAxel Dörfler	registeredNode.input_list.clear();
4789c3b4706SAxel Dörfler
4799c3b4706SAxel Dörfler	try {
4809c3b4706SAxel Dörfler		for (int32 i = 0; i < count; i++)
4819c3b4706SAxel Dörfler			registeredNode.input_list.push_back(inputs[i]);
4829c3b4706SAxel Dörfler	} catch (std::bad_alloc& exception) {
4839c3b4706SAxel Dörfler		return B_NO_MEMORY;
4849c3b4706SAxel Dörfler	}
4859c3b4706SAxel Dörfler
486d9b7ae21Sbeveloper	return B_OK;
487d9b7ae21Sbeveloper}
488d9b7ae21Sbeveloper
489d9b7ae21Sbeveloper
490d9b7ae21Sbeveloperstatus_t
4919c3b4706SAxel DörflerNodeManager::PublishOutputs(const media_node &node, const media_output* outputs,
4929c3b4706SAxel Dörfler	int32 count)
493d9b7ae21Sbeveloper{
4949c3b4706SAxel Dörfler	BAutolock _(this);
4959c3b4706SAxel Dörfler
4969c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(node.node);
4979c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
498fe1f74abSJérôme Duval		ERROR("NodeManager::PublishOutputs: node %" B_PRId32 " not found\n",
499fe1f74abSJérôme Duval			node.node);
5001299bfb2Sbeveloper		return B_ERROR;
5011299bfb2Sbeveloper	}
5029c3b4706SAxel Dörfler
5039c3b4706SAxel Dörfler	registered_node& registeredNode = found->second;
5049c3b4706SAxel Dörfler
5059c3b4706SAxel Dörfler	registeredNode.output_list.clear();
5069c3b4706SAxel Dörfler
5079c3b4706SAxel Dörfler	try {
5089c3b4706SAxel Dörfler		for (int32 i = 0; i < count; i++)
5099c3b4706SAxel Dörfler			registeredNode.output_list.push_back(outputs[i]);
5109c3b4706SAxel Dörfler	} catch (std::bad_alloc& exception) {
5119c3b4706SAxel Dörfler		return B_NO_MEMORY;
5129c3b4706SAxel Dörfler	}
5139c3b4706SAxel Dörfler
514d9b7ae21Sbeveloper	return B_OK;
515d9b7ae21Sbeveloper}
516d9b7ae21Sbeveloper
517d9b7ae21Sbeveloper
518d9b7ae21Sbeveloperstatus_t
5199c3b4706SAxel DörflerNodeManager::FindNodeID(port_id port, media_node_id* _id)
520d9b7ae21Sbeveloper{
5219c3b4706SAxel Dörfler	BAutolock _(this);
5229c3b4706SAxel Dörfler
5239c3b4706SAxel Dörfler	NodeMap::iterator iterator = fNodeMap.begin();
5249c3b4706SAxel Dörfler	for (; iterator != fNodeMap.end(); iterator++) {
5259c3b4706SAxel Dörfler		registered_node& node = iterator->second;
5269c3b4706SAxel Dörfler
5279c3b4706SAxel Dörfler		if (node.port == port) {
5289c3b4706SAxel Dörfler			*_id = node.node_id;
529fe1f74abSJérôme Duval			TRACE("NodeManager::FindNodeID found port %" B_PRId32 ", node %"
530fe1f74abSJérôme Duval				B_PRId32 "\n", port, node.node_id);
5311299bfb2Sbeveloper			return B_OK;
5321299bfb2Sbeveloper		}
5339c3b4706SAxel Dörfler
5349c3b4706SAxel Dörfler		OutputList::iterator outIterator = node.output_list.begin();
5359c3b4706SAxel Dörfler		for (; outIterator != node.output_list.end(); outIterator++) {
5369c3b4706SAxel Dörfler			if (outIterator->source.port == port) {
5379c3b4706SAxel Dörfler				*_id = node.node_id;
538fe1f74abSJérôme Duval				TRACE("NodeManager::FindNodeID found output port %" B_PRId32
539fe1f74abSJérôme Duval					", node %" B_PRId32 "\n", port, node.node_id);
5401299bfb2Sbeveloper				return B_OK;
5411299bfb2Sbeveloper			}
5421299bfb2Sbeveloper		}
5439c3b4706SAxel Dörfler
5449c3b4706SAxel Dörfler		InputList::iterator inIterator = node.input_list.begin();
5459c3b4706SAxel Dörfler		for (; inIterator != node.input_list.end(); inIterator++) {
5469c3b4706SAxel Dörfler			if (inIterator->destination.port == port) {
5479c3b4706SAxel Dörfler				*_id = node.node_id;
548fe1f74abSJérôme Duval				TRACE("NodeManager::FindNodeID found input port %" B_PRId32
549fe1f74abSJérôme Duval					", node %" B_PRId32 "\n", port, node.node_id);
5501299bfb2Sbeveloper				return B_OK;
5511299bfb2Sbeveloper			}
5521299bfb2Sbeveloper		}
5531299bfb2Sbeveloper	}
5549c3b4706SAxel Dörfler
555fe1f74abSJérôme Duval	ERROR("NodeManager::FindNodeID failed, port %" B_PRId32 "\n", port);
5561299bfb2Sbeveloper	return B_ERROR;
557d9b7ae21Sbeveloper}
558d9b7ae21Sbeveloper
5599dec2310SAxel Dörfler
560626824eaSbeveloperstatus_t
5619c3b4706SAxel DörflerNodeManager::GetDormantNodeInfo(const media_node& node,
5629c3b4706SAxel Dörfler	dormant_node_info* nodeInfo)
563626824eaSbeveloper{
5649c3b4706SAxel Dörfler	// TODO: not sure if this is correct
5659c3b4706SAxel Dörfler	BAutolock _(this);
5669c3b4706SAxel Dörfler
5679c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(node.node);
5689c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
569fe1f74abSJérôme Duval		ERROR("NodeManager::GetDormantNodeInfo: node %" B_PRId32 " not found"
570fe1f74abSJérôme Duval			"\n", node.node);
5719c3b4706SAxel Dörfler		return B_ERROR;
572626824eaSbeveloper	}
5739c3b4706SAxel Dörfler
5749c3b4706SAxel Dörfler	registered_node& registeredNode = found->second;
5759c3b4706SAxel Dörfler
5769c3b4706SAxel Dörfler	if (registeredNode.add_on_id == -1
5779c3b4706SAxel Dörfler		&& node.node != NODE_SYSTEM_TIMESOURCE_ID) {
5789c3b4706SAxel Dörfler		// This function must return an error if the node is application owned
5799c3b4706SAxel Dörfler		TRACE("NodeManager::GetDormantNodeInfo NODE IS APPLICATION OWNED! "
580fe1f74abSJérôme Duval			"node %" B_PRId32 ", add_on_id %" B_PRId32 ", flavor_id %" B_PRId32
581fe1f74abSJérôme Duval			", name \"%s\"\n", node.node, registeredNode.add_on_id,
582fe1f74abSJérôme Duval			registeredNode.flavor_id, registeredNode.name);
5839c3b4706SAxel Dörfler		return B_ERROR;
5849c3b4706SAxel Dörfler	}
5859c3b4706SAxel Dörfler
5869c3b4706SAxel Dörfler	ASSERT(node.port == registeredNode.port);
5879c3b4706SAxel Dörfler	ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
5889c3b4706SAxel Dörfler		== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
5899c3b4706SAxel Dörfler
5909c3b4706SAxel Dörfler	nodeInfo->addon = registeredNode.add_on_id;
5919c3b4706SAxel Dörfler	nodeInfo->flavor_id = registeredNode.flavor_id;
5929c3b4706SAxel Dörfler	strlcpy(nodeInfo->name, registeredNode.name, sizeof(nodeInfo->name));
5939c3b4706SAxel Dörfler
594fe1f74abSJérôme Duval	TRACE("NodeManager::GetDormantNodeInfo node %" B_PRId32 ", add_on_id %"
595fe1f74abSJérôme Duval		B_PRId32 ", flavor_id %" B_PRId32 ", name \"%s\"\n", node.node,
596fe1f74abSJérôme Duval		registeredNode.add_on_id, registeredNode.flavor_id,
597fe1f74abSJérôme Duval		registeredNode.name);
5989c3b4706SAxel Dörfler	return B_OK;
599626824eaSbeveloper}
600d9b7ae21Sbeveloper
6019dec2310SAxel Dörfler
602d9b7ae21Sbeveloperstatus_t
6039c3b4706SAxel DörflerNodeManager::GetLiveNodeInfo(const media_node& node, live_node_info* liveInfo)
604d9b7ae21Sbeveloper{
6059c3b4706SAxel Dörfler	BAutolock _(this);
6069c3b4706SAxel Dörfler
6079c3b4706SAxel Dörfler	NodeMap::iterator found = fNodeMap.find(node.node);
6089c3b4706SAxel Dörfler	if (found == fNodeMap.end()) {
609fe1f74abSJérôme Duval		ERROR("NodeManager::GetLiveNodeInfo: node %" B_PRId32 " not found\n",
6109c3b4706SAxel Dörfler			node.node);
6119c3b4706SAxel Dörfler		return B_ERROR;
6121299bfb2Sbeveloper	}
6139c3b4706SAxel Dörfler
6149c3b4706SAxel Dörfler	registered_node& registeredNode = found->second;
6159c3b4706SAxel Dörfler
6169c3b4706SAxel Dörfler	ASSERT(node.port == registeredNode.port);
6179c3b4706SAxel Dörfler	ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
6189c3b4706SAxel Dörfler		== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
6199c3b4706SAxel Dörfler
6209c3b4706SAxel Dörfler	liveInfo->node = node;
6219c3b4706SAxel Dörfler	liveInfo->hint_point = BPoint(0, 0);
6229c3b4706SAxel Dörfler	strlcpy(liveInfo->name, registeredNode.name, sizeof(liveInfo->name));
6239c3b4706SAxel Dörfler
624fe1f74abSJérôme Duval	TRACE("NodeManager::GetLiveNodeInfo node %" B_PRId32 ", name = \"%s\"\n",
625fe1f74abSJérôme Duval		node.node, registeredNode.name);
6269c3b4706SAxel Dörfler	return B_OK;
627d9b7ae21