xref: /haiku/src/servers/media/NodeManager.cpp (revision b073975e186497a1aa0a16832fd23827591faa98)
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 <MediaDebug.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*
get_node_type(node_type type)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 
NodeManager()77 NodeManager::NodeManager()
78 	:
79 	BLocker("node manager"),
80 	fNextAddOnID(1),
81 	fNextNodeID(1),
82 	fDefaultManager(new DefaultManager)
83 {
84 }
85 
86 
~NodeManager()87 NodeManager::~NodeManager()
88 {
89 	delete fDefaultManager;
90 }
91 
92 
93 // #pragma mark - Default node management
94 
95 
96 status_t
SetDefaultNode(node_type type,const media_node * node,const dormant_node_info * info,const media_input * input)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
GetDefaultNode(node_type type,media_node_id * _nodeID,char * inputName,int32 * _inputID)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
RescanDefaultNodes()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
RegisterNode(media_addon_id addOnID,int32 flavorID,const char * name,uint64 kinds,port_id port,team_id team,media_node_id timesource,media_node_id * _nodeID)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 %#" B_PRIx64", port %"
191 		B_PRId32 ", team %" B_PRId32 "\n", *_nodeID, addOnID, flavorID, name,
192 		kinds, port, team);
193 	return B_OK;
194 }
195 
196 
197 status_t
UnregisterNode(media_node_id id,team_id team,media_addon_id * _addOnID,int32 * _flavorID)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
ReleaseNodeReference(media_node_id id,team_id team)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
ReleaseNodeAll(media_node_id id)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
SetNodeCreator(media_node_id id,team_id creator)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
GetCloneForID(media_node_id id,team_id team,media_node * node)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
GetClone(node_type type,team_id team,media_node * node,char * inputName,int32 * _inputID)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 %#" B_PRIx64 "\n", node->node, node->port,
443 		node->kind);
444 	return B_OK;
445 }
446 
447 
448 status_t
ReleaseNode(const media_node & node,team_id team)449 NodeManager::ReleaseNode(const media_node& node, team_id team)
450 {
451 	TRACE("NodeManager::ReleaseNode enter: node %" B_PRId32 " team %" B_PRId32
452 		"\n", node.node, team);
453 
454 	if (ReleaseNodeReference(node.node, team) != B_OK) {
455 		ERROR("NodeManager::ReleaseNode: couldn't decrement node %" B_PRId32
456 			" team %" B_PRId32 " ref count\n", node.node, team);
457 	}
458 
459 	return B_OK;
460 }
461 
462 
463 status_t
PublishInputs(const media_node & node,const media_input * inputs,int32 count)464 NodeManager::PublishInputs(const media_node& node, const media_input* inputs,
465 	int32 count)
466 {
467 	BAutolock _(this);
468 
469 	NodeMap::iterator found = fNodeMap.find(node.node);
470 	if (found == fNodeMap.end()) {
471 		ERROR("NodeManager::PublishInputs: node %" B_PRId32 " not found\n",
472 			node.node);
473 		return B_ERROR;
474 	}
475 
476 	registered_node& registeredNode = found->second;
477 
478 	registeredNode.input_list.clear();
479 
480 	try {
481 		for (int32 i = 0; i < count; i++)
482 			registeredNode.input_list.push_back(inputs[i]);
483 	} catch (std::bad_alloc& exception) {
484 		return B_NO_MEMORY;
485 	}
486 
487 	return B_OK;
488 }
489 
490 
491 status_t
PublishOutputs(const media_node & node,const media_output * outputs,int32 count)492 NodeManager::PublishOutputs(const media_node &node, const media_output* outputs,
493 	int32 count)
494 {
495 	BAutolock _(this);
496 
497 	NodeMap::iterator found = fNodeMap.find(node.node);
498 	if (found == fNodeMap.end()) {
499 		ERROR("NodeManager::PublishOutputs: node %" B_PRId32 " not found\n",
500 			node.node);
501 		return B_ERROR;
502 	}
503 
504 	registered_node& registeredNode = found->second;
505 
506 	registeredNode.output_list.clear();
507 
508 	try {
509 		for (int32 i = 0; i < count; i++)
510 			registeredNode.output_list.push_back(outputs[i]);
511 	} catch (std::bad_alloc& exception) {
512 		return B_NO_MEMORY;
513 	}
514 
515 	return B_OK;
516 }
517 
518 
519 status_t
FindNodeID(port_id port,media_node_id * _id)520 NodeManager::FindNodeID(port_id port, media_node_id* _id)
521 {
522 	BAutolock _(this);
523 
524 	NodeMap::iterator iterator = fNodeMap.begin();
525 	for (; iterator != fNodeMap.end(); iterator++) {
526 		registered_node& node = iterator->second;
527 
528 		if (node.port == port) {
529 			*_id = node.node_id;
530 			TRACE("NodeManager::FindNodeID found port %" B_PRId32 ", node %"
531 				B_PRId32 "\n", port, node.node_id);
532 			return B_OK;
533 		}
534 
535 		OutputList::iterator outIterator = node.output_list.begin();
536 		for (; outIterator != node.output_list.end(); outIterator++) {
537 			if (outIterator->source.port == port) {
538 				*_id = node.node_id;
539 				TRACE("NodeManager::FindNodeID found output port %" B_PRId32
540 					", node %" B_PRId32 "\n", port, node.node_id);
541 				return B_OK;
542 			}
543 		}
544 
545 		InputList::iterator inIterator = node.input_list.begin();
546 		for (; inIterator != node.input_list.end(); inIterator++) {
547 			if (inIterator->destination.port == port) {
548 				*_id = node.node_id;
549 				TRACE("NodeManager::FindNodeID found input port %" B_PRId32
550 					", node %" B_PRId32 "\n", port, node.node_id);
551 				return B_OK;
552 			}
553 		}
554 	}
555 
556 	ERROR("NodeManager::FindNodeID failed, port %" B_PRId32 "\n", port);
557 	return B_ERROR;
558 }
559 
560 
561 status_t
GetDormantNodeInfo(const media_node & node,dormant_node_info * nodeInfo)562 NodeManager::GetDormantNodeInfo(const media_node& node,
563 	dormant_node_info* nodeInfo)
564 {
565 	// TODO: not sure if this is correct
566 	BAutolock _(this);
567 
568 	NodeMap::iterator found = fNodeMap.find(node.node);
569 	if (found == fNodeMap.end()) {
570 		ERROR("NodeManager::GetDormantNodeInfo: node %" B_PRId32 " not found"
571 			"\n", node.node);
572 		return B_ERROR;
573 	}
574 
575 	registered_node& registeredNode = found->second;
576 
577 	if (registeredNode.add_on_id == -1
578 		&& node.node != NODE_SYSTEM_TIMESOURCE_ID) {
579 		// This function must return an error if the node is application owned
580 		TRACE("NodeManager::GetDormantNodeInfo NODE IS APPLICATION OWNED! "
581 			"node %" B_PRId32 ", add_on_id %" B_PRId32 ", flavor_id %" B_PRId32
582 			", name \"%s\"\n", node.node, registeredNode.add_on_id,
583 			registeredNode.flavor_id, registeredNode.name);
584 		return B_ERROR;
585 	}
586 
587 	ASSERT(node.port == registeredNode.port);
588 	ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
589 		== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
590 
591 	nodeInfo->addon = registeredNode.add_on_id;
592 	nodeInfo->flavor_id = registeredNode.flavor_id;
593 	strlcpy(nodeInfo->name, registeredNode.name, sizeof(nodeInfo->name));
594 
595 	TRACE("NodeManager::GetDormantNodeInfo node %" B_PRId32 ", add_on_id %"
596 		B_PRId32 ", flavor_id %" B_PRId32 ", name \"%s\"\n", node.node,
597 		registeredNode.add_on_id, registeredNode.flavor_id,
598 		registeredNode.name);
599 	return B_OK;
600 }
601 
602 
603 status_t
GetLiveNodeInfo(const media_node & node,live_node_info * liveInfo)604 NodeManager::GetLiveNodeInfo(const media_node& node, live_node_info* liveInfo)
605 {
606 	BAutolock _(this);
607 
608 	NodeMap::iterator found = fNodeMap.find(node.node);
609 	if (found == fNodeMap.end()) {
610 		ERROR("NodeManager::GetLiveNodeInfo: node %" B_PRId32 " not found\n",
611 			node.node);
612 		return B_ERROR;
613 	}
614 
615 	registered_node& registeredNode = found->second;
616 
617 	ASSERT(node.port == registeredNode.port);
618 	ASSERT((node.kind & NODE_KIND_COMPARE_MASK)
619 		== (registeredNode.kinds & NODE_KIND_COMPARE_MASK));
620 
621 	liveInfo->node = node;
622 	liveInfo->hint_point = BPoint(0, 0);
623 	strlcpy(liveInfo->name, registeredNode.name, sizeof(liveInfo->name));
624 
625 	TRACE("NodeManager::GetLiveNodeInfo node %" B_PRId32 ", name = \"%s\"\n",
626 		node.node, registeredNode.name);
627 	return B_OK;
628 }
629 
630 
631 status_t
GetInstances(media_addon_id addOnID,int32 flavorID,media_node_id * ids,int32 * _count,int32 maxCount)632 NodeManager::GetInstances(media_addon_id addOnID, int32 flavorID,
633 	media_node_id* ids, int32* _count, int32 maxCount)
634 {
635 	BAutolock _(this);
636 
637 	NodeMap::iterator iterator = fNodeMap.begin();
638 	int32 count = 0;
639 	for (; iterator != fNodeMap.end() && count < maxCount; iterator++) {
640 		registered_node& node = iterator->second;
641 
642 		if (node.add_on_id == addOnID && node.flavor_id == flavorID)
643 			ids[count++] = node.node_id;
644 	}
645 
646 	TRACE("NodeManager::GetInstances found %" B_PRId32 " instances for "
647 		"addon_id %" B_PRId32 ", flavor_id %" B_PRId32 "\n", count, addOnID,
648 		flavorID);
649 	*_count = count;
650 	return B_OK;
651 }
652 
653 
654 status_t
GetLiveNodes(LiveNodeList & liveNodes,int32 maxCount,const media_format * inputFormat,const media_format * outputFormat,const char * name,uint64 requireKinds)655 NodeManager::GetLiveNodes(LiveNodeList& liveNodes, int32 maxCount,
656 	const media_format* inputFormat, const media_format* outputFormat,
657 	const char* name, uint64 requireKinds)
658 {
659 	TRACE("NodeManager::GetLiveNodes: maxCount %" B_PRId32 ", in-format %p, "
660 		"out-format %p, name %s, require kinds 0x%" B_PRIx64 "\n", maxCount,
661 		inputFormat, outputFormat, name != NULL ? name : "NULL", requireKinds);
662 
663 	BAutolock _(this);
664 
665 	// Determine the count of byte to compare when checking for a name with
666 	// or without wildcard
667 	size_t nameLength = 0;
668 	if (name != NULL) {
669 		nameLength = strlen(name);
670 		if (nameLength > 0 && name[nameLength - 1] == '*')
671 			nameLength--;
672 	}
673 
674 	NodeMap::iterator iterator = fNodeMap.begin();
675 	int32 count = 0;
676 	for (; iterator != fNodeMap.end() && count < maxCount; iterator++) {
677 		registered_node& node = iterator->second;
678 
679 		if ((node.kinds & requireKinds) != requireKinds)
680 			continue;
681 
682 		if (nameLength != 0) {
683 			if (strncmp(name, node.name, nameLength) != 0)
684 				continue;
685 		}
686 
687 		if (inputFormat != NULL) {
688 			bool found = false;
689 
690 			for (InputList::iterator inIterator = node.input_list.begin();
691 					inIterator != node.input_list.end(); inIterator++) {
692 				media_input& input = *inIterator;
693 
694 				if (format_is_compatible(*inputFormat, input.format)) {
695 					found = true;
696 					break;
697 				}
698 			}
699 
700 			if (!found)
701 				continue;
702 		}
703 
704 		if (outputFormat != NULL) {
705 			bool found = false;
706 
707 			for (OutputList::iterator outIterator = node.output_list.begin();
708 					outIterator != node.output_list.end(); outIterator++) {
709 				media_output& output = *outIterator;
710 
711 				if (format_is_compatible(*outputFormat, output.format)) {
712 					found = true;
713 					break;
714 				}
715 			}
716 
717 			if (!found)
718 				continue;
719 		}
720 
721 		live_node_info info;
722 		info.node.node = node.node_id;
723 		info.node.port = node.port;
724 		info.node.kind = node.kinds;
725 		info.hint_point = BPoint(0, 0);
726 		strlcpy(info.name, node.name, sizeof(info.name));
727 
728 		try {
729 			liveNodes.push_back(info);
730 		} catch (std::bad_alloc& exception) {
731 			return B_NO_MEMORY;
732 		}
733 
734 		count++;
735 	}
736 
737 	TRACE("NodeManager::GetLiveNodes found %" B_PRId32 "\n", count);
738 	return B_OK;
739 }
740 
741 
742 /*!	Add media_node_id of all live nodes to the message
743 	int32 "media_node_id" (multiple items)
744 */
745 status_t
GetLiveNodes(BMessage * message)746 NodeManager::GetLiveNodes(BMessage* message)
747 {
748 	BAutolock _(this);
749 
750 	NodeMap::iterator iterator = fNodeMap.begin();
751 	for (; iterator != fNodeMap.end(); iterator++) {
752 		registered_node& node = iterator->second;
753 
754 		if (message->AddInt32("media_node_id", node.node_id) != B_OK)
755 			return B_NO_MEMORY;
756 	}
757 
758 	return B_OK;
759 }
760 
761 
762 // #pragma mark - Registration of BMediaAddOns
763 
764 
765 void
RegisterAddOn(const entry_ref & ref,media_addon_id * _newID)766 NodeManager::RegisterAddOn(const entry_ref& ref, media_addon_id* _newID)
767 {
768 	BAutolock _(this);
769 
770 	media_addon_id id = fNextAddOnID++;
771 
772 //	printf("NodeManager::RegisterAddOn: ref-name \"%s\", assigning id %"
773 //		B_PRId32 "\n", ref.name, id);
774 
775 	try {
776 		fPathMap.insert(std::make_pair(id, ref));
777 		*_newID = id;
778 	} catch (std::bad_alloc& exception) {
779 		*_newID = -1;
780 	}
781 }
782 
783 
784 void
UnregisterAddOn(media_addon_id addOnID)785 NodeManager::UnregisterAddOn(media_addon_id addOnID)
786 {
787 	PRINT(1, "NodeManager::UnregisterAddOn: id %" B_PRId32 "\n", addOnID);
788 
789 	BAutolock _(this);
790 
791 	RemoveDormantFlavorInfo(addOnID);
792 	fPathMap.erase(addOnID);
793 }
794 
795 
796 status_t
GetAddOnRef(media_addon_id addOnID,entry_ref * ref)797 NodeManager::GetAddOnRef(media_addon_id addOnID, entry_ref* ref)
798 {
799 	BAutolock _(this);
800 
801 	PathMap::iterator found = fPathMap.find(addOnID);
802 	if (found == fPathMap.end())
803 		return B_ERROR;
804 
805 	*ref = found->second;
806 	return B_OK;
807 }
808 
809 
810 // #pragma mark - Registration of node flavors, published by BMediaAddOns
811 
812 
813 //!	This function is only used (indirectly) by the media_addon_server.
814 status_t
AddDormantFlavorInfo(const dormant_flavor_info & flavorInfo)815 NodeManager::AddDormantFlavorInfo(const dormant_flavor_info& flavorInfo)
816 {
817 	PRINT(1, "NodeManager::AddDormantFlavorInfo, addon-id %" B_PRId32 ", "
818 		"flavor-id %" B_PRId32 ", name \"%s\", flavor-name \"%s\", flavor-info"
819 		" \"%s\"\n", flavorInfo.node_info.addon,
820 		flavorInfo.node_info.flavor_id, flavorInfo.node_info.name,
821 		flavorInfo.name, flavorInfo.info);
822 
823 	BAutolock _(this);
824 
825 	// Try to find the addon-id/flavor-id in the list.
826 	// If it already exists, update the info, but don't change its instance
827 	// count.
828 
829 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
830 			iterator != fDormantFlavors.end(); iterator++) {
831 		dormant_add_on_flavor_info& info = *iterator;
832 
833 		if (info.add_on_id != flavorInfo.node_info.addon
834 			|| info.flavor_id != flavorInfo.node_info.flavor_id)
835 			continue;
836 
837 		if (info.info_valid) {
838 			ERROR("NodeManager::AddDormantFlavorInfo, addon-id %" B_PRId32 ", "
839 				"flavor-id %" B_PRId32 " does already exist\n",
840 				info.info.node_info.addon, info.info.node_info.flavor_id);
841 		}
842 
843 		TRACE("NodeManager::AddDormantFlavorInfo, updating addon-id %" B_PRId32
844 			", flavor-id %" B_PRId32 "\n", info.info.node_info.addon,
845 			info.info.node_info.flavor_id);
846 
847 		info.max_instances_count = flavorInfo.possible_count > 0
848 			? flavorInfo.possible_count : INT32_MAX;
849 		info.info_valid = true;
850 		info.info = flavorInfo;
851 		return B_OK;
852 	}
853 
854 	// Insert information into the list
855 
856 	dormant_add_on_flavor_info info;
857 	info.add_on_id = flavorInfo.node_info.addon;
858 	info.flavor_id = flavorInfo.node_info.flavor_id;
859 	info.max_instances_count = flavorInfo.possible_count > 0
860 		? flavorInfo.possible_count : INT32_MAX;
861 	info.instances_count = 0;
862 	info.info_valid = true;
863 	info.info = flavorInfo;
864 
865 	try {
866 		fDormantFlavors.push_back(info);
867 	} catch (std::bad_alloc& exception) {
868 		return B_NO_MEMORY;
869 	}
870 
871 	return B_OK;
872 }
873 
874 
875 //!	This function is only used (indirectly) by the media_addon_server
876 void
InvalidateDormantFlavorInfo(media_addon_id addOnID)877 NodeManager::InvalidateDormantFlavorInfo(media_addon_id addOnID)
878 {
879 	BAutolock _(this);
880 
881 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
882 			iterator != fDormantFlavors.end(); iterator++) {
883 		dormant_add_on_flavor_info& info = *iterator;
884 
885 		if (info.add_on_id == addOnID && info.info_valid) {
886 			PRINT(1, "NodeManager::InvalidateDormantFlavorInfo, addon-id %"
887 				B_PRId32 ", flavor-id %" B_PRId32 ", name \"%s\", flavor-name "
888 				"\"%s\", flavor-info \"%s\"\n", info.info.node_info.addon,
889 				info.info.node_info.flavor_id, info.info.node_info.name,
890 				info.info.name, info.info.info);
891 
892 			info.info_valid = false;
893 		}
894 	}
895 }
896 
897 
898 //!	This function is only used (indirectly) by the media_addon_server
899 void
RemoveDormantFlavorInfo(media_addon_id addOnID)900 NodeManager::RemoveDormantFlavorInfo(media_addon_id addOnID)
901 {
902 	BAutolock _(this);
903 
904 	for (size_t index = 0; index < fDormantFlavors.size(); index++) {
905 		dormant_add_on_flavor_info& info = fDormantFlavors[index];
906 
907 		if (info.add_on_id == addOnID) {
908 			PRINT(1, "NodeManager::RemoveDormantFlavorInfo, addon-id %"
909 				B_PRId32 ", flavor-id %" B_PRId32 ", name \"%s\", flavor-name "
910 				"\"%s\", flavor-info \"%s\"\n", info.info.node_info.addon,
911 				info.info.node_info.flavor_id, info.info.node_info.name,
912 				info.info.name, info.info.info);
913 			fDormantFlavors.erase(fDormantFlavors.begin() + index--);
914 		}
915 	}
916 }
917 
918 
919 status_t
IncrementFlavorInstancesCount(media_addon_id addOnID,int32 flavorID,team_id team)920 NodeManager::IncrementFlavorInstancesCount(media_addon_id addOnID,
921 	int32 flavorID, team_id team)
922 {
923 	BAutolock _(this);
924 
925 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
926 			iterator != fDormantFlavors.end(); iterator++) {
927 		dormant_add_on_flavor_info& info = *iterator;
928 
929 		if (info.add_on_id != addOnID || info.flavor_id != flavorID)
930 			continue;
931 
932 		if (info.instances_count >= info.max_instances_count) {
933 			// maximum (or more) instances already exist
934 			ERROR("NodeManager::IncrementFlavorInstancesCount addon-id %"
935 				B_PRId32 ", flavor-id %" B_PRId32 " maximum (or more) "
936 				"instances already exist\n", addOnID, flavorID);
937 			return B_ERROR;
938 		}
939 
940 		TeamCountMap::iterator teamInstance
941 			= info.team_instances_count.find(team);
942 		if (teamInstance == info.team_instances_count.end()) {
943 			// This is the team's first instance
944 			try {
945 				info.team_instances_count.insert(std::make_pair(team, 1));
946 			} catch (std::bad_alloc& exception) {
947 				return B_NO_MEMORY;
948 			}
949 		} else {
950 			// Just increase its ref count
951 			teamInstance->second++;
952 		}
953 
954 		info.instances_count++;
955 		return B_OK;
956 	}
957 
958 	ERROR("NodeManager::IncrementFlavorInstancesCount addon-id %" B_PRId32 ", "
959 		"flavor-id %" B_PRId32 " not found\n", addOnID, flavorID);
960 	return B_ERROR;
961 }
962 
963 
964 status_t
DecrementFlavorInstancesCount(media_addon_id addOnID,int32 flavorID,team_id team)965 NodeManager::DecrementFlavorInstancesCount(media_addon_id addOnID,
966 	int32 flavorID, team_id team)
967 {
968 	BAutolock _(this);
969 
970 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
971 			iterator != fDormantFlavors.end(); iterator++) {
972 		dormant_add_on_flavor_info& info = *iterator;
973 
974 		if (info.add_on_id != addOnID || info.flavor_id != flavorID)
975 			continue;
976 
977 		TeamCountMap::iterator teamInstance
978 			= info.team_instances_count.find(team);
979 		if (teamInstance == info.team_instances_count.end()) {
980 			ERROR("NodeManager::DecrementFlavorInstancesCount addon-id %"
981 				B_PRId32 ", flavor-id %" B_PRId32 " team %" B_PRId32 " has no "
982 				"references\n", addOnID, flavorID, team);
983 			return B_ERROR;
984 		}
985 		if (--teamInstance->second == 0)
986 			info.team_instances_count.erase(teamInstance);
987 
988 		info.instances_count--;
989 		return B_OK;
990 	}
991 
992 	ERROR("NodeManager::DecrementFlavorInstancesCount addon-id %" B_PRId32 ", "
993 		"flavor-id %" B_PRId32 " not found\n", addOnID, flavorID);
994 	return B_ERROR;
995 }
996 
997 
998 //!	This function is called when the media_addon_server has crashed
999 void
CleanupDormantFlavorInfos()1000 NodeManager::CleanupDormantFlavorInfos()
1001 {
1002 	PRINT(1, "NodeManager::CleanupDormantFlavorInfos\n");
1003 
1004 	BAutolock _(this);
1005 
1006 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1007 			iterator != fDormantFlavors.end(); iterator++) {
1008 		dormant_add_on_flavor_info& info = *iterator;
1009 
1010 		// Current instance count is zero since the media_addon_server crashed.
1011 		BPrivate::media::notifications::FlavorsChanged(info.add_on_id,
1012 			0, info.instances_count);
1013 	}
1014 
1015 	fDormantFlavors.clear();
1016 
1017 	PRINT(1, "NodeManager::CleanupDormantFlavorInfos done\n");
1018 }
1019 
1020 
1021 status_t
GetDormantNodes(dormant_node_info * infos,int32 * _count,const media_format * input,const media_format * output,const char * name,uint64 requireKinds,uint64 denyKinds)1022 NodeManager::GetDormantNodes(dormant_node_info* infos, int32* _count,
1023 	const media_format* input, const media_format* output, const char* name,
1024 	uint64 requireKinds, uint64 denyKinds)
1025 {
1026 	BAutolock _(this);
1027 
1028 	// Determine the count of byte to compare when checking for a name with
1029 	// or without wildcard
1030 	size_t nameLength = 0;
1031 	if (name != NULL) {
1032 		nameLength = strlen(name);
1033 		if (nameLength > 0 && name[nameLength - 1] == '*')
1034 			nameLength--;
1035 	}
1036 
1037 	int32 maxCount = *_count;
1038 	int32 count = 0;
1039 
1040 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1041 			iterator != fDormantFlavors.end() && count < maxCount; iterator++) {
1042 		dormant_add_on_flavor_info& info = *iterator;
1043 
1044 		if (!info.info_valid)
1045 			continue;
1046 
1047 		if ((info.info.kinds & requireKinds) != requireKinds
1048 			|| (info.info.kinds & denyKinds) != 0)
1049 			continue;
1050 
1051 		if (nameLength != 0) {
1052 			if (strncmp(name, info.info.name, nameLength) != 0)
1053 				continue;
1054 		}
1055 
1056 		if (input != NULL) {
1057 			bool found = false;
1058 
1059 			for (int32 i = 0; i < info.info.in_format_count; i++) {
1060 				if (format_is_compatible(*input, info.info.in_formats[i])) {
1061 					found = true;
1062 					break;
1063 				}
1064 			}
1065 
1066 			if (!found)
1067 				continue;
1068 		}
1069 
1070 		if (output != NULL) {
1071 			bool found = false;
1072 
1073 			for (int32 i = 0; i < info.info.out_format_count; i++) {
1074 				if (format_is_compatible(*output, info.info.out_formats[i])) {
1075 					found = true;
1076 					break;
1077 				}
1078 			}
1079 
1080 			if (!found)
1081 				continue;
1082 		}
1083 
1084 		infos[count++] = info.info.node_info;
1085 	}
1086 
1087 	*_count = count;
1088 	return B_OK;
1089 }
1090 
1091 
1092 status_t
GetDormantFlavorInfoFor(media_addon_id addOnID,int32 flavorID,dormant_flavor_info * flavorInfo)1093 NodeManager::GetDormantFlavorInfoFor(media_addon_id addOnID, int32 flavorID,
1094 	dormant_flavor_info* flavorInfo)
1095 {
1096 	BAutolock _(this);
1097 
1098 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1099 			iterator != fDormantFlavors.end(); iterator++) {
1100 		dormant_add_on_flavor_info& info = *iterator;
1101 
1102 		if (info.add_on_id == addOnID && info.flavor_id == flavorID
1103 			&& info.info_valid) {
1104 			*flavorInfo = info.info;
1105 			return B_OK;
1106 		}
1107 	}
1108 
1109 	return B_ERROR;
1110 }
1111 
1112 
1113 // #pragma mark - Misc.
1114 
1115 
1116 status_t
SetNodeTimeSource(media_node_id node,media_node_id timesource)1117 NodeManager::SetNodeTimeSource(media_node_id node,
1118 	media_node_id timesource)
1119 {
1120 	BAutolock _(this);
1121 
1122 	NodeMap::iterator found = fNodeMap.find(node);
1123 	if (found == fNodeMap.end()) {
1124 		ERROR("NodeManager::SetNodeTimeSource: node %"
1125 			B_PRId32 " not found\n", node);
1126 		return B_ERROR;
1127 	}
1128 	registered_node& registeredNode = found->second;
1129 	registeredNode.timesource_id = timesource;
1130 	return B_OK;
1131 }
1132 
1133 
1134 void
CleanupTeam(team_id team)1135 NodeManager::CleanupTeam(team_id team)
1136 {
1137 	BAutolock _(this);
1138 
1139 	fDefaultManager->CleanupTeam(team);
1140 
1141 	PRINT(1, "NodeManager::CleanupTeam: team %" B_PRId32 "\n", team);
1142 
1143 	// Cleanup node references
1144 
1145 	for (NodeMap::iterator iterator = fNodeMap.begin();
1146 			iterator != fNodeMap.end();) {
1147 		registered_node& node = iterator->second;
1148 		NodeMap::iterator remove = iterator++;
1149 
1150 		// If the gone team was the creator of some global dormant node
1151 		// instance, we now invalidate that we may want to remove that
1152 		// global node, but I'm not sure
1153 		if (node.creator == team) {
1154 			node.creator = -1;
1155 			// fall through
1156 		}
1157 
1158 		// If the team hosting this node is gone, remove node from database
1159 		if (node.containing_team == team) {
1160 			PRINT(1, "NodeManager::CleanupTeam: removing node id %" B_PRId32
1161 				", team %" B_PRId32 "\n", node.node_id, team);
1162 			// Ensure the slave node is removed from it's timesource
1163 			_NotifyTimeSource(node);
1164 			fNodeMap.erase(remove);
1165 			BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
1166 			continue;
1167 		}
1168 
1169 		// Check the list of teams that have references to this node, and
1170 		// remove the team
1171 		TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
1172 		if (teamRef != node.team_ref_count.end()) {
1173 			PRINT(1, "NodeManager::CleanupTeam: removing %" B_PRId32 " refs "
1174 				"from node id %" B_PRId32 ", team %" B_PRId32 "\n",
1175 				teamRef->second, node.node_id, team);
1176 			node.ref_count -= teamRef->second;
1177 			if (node.ref_count == 0) {
1178 				PRINT(1, "NodeManager::CleanupTeam: removing node id %"
1179 					B_PRId32 " that has no teams\n", node.node_id);
1180 
1181 				// Ensure the slave node is removed from it's timesource
1182 				_NotifyTimeSource(node);
1183 				fNodeMap.erase(remove);
1184 				BPrivate::media::notifications::NodesDeleted(&node.node_id, 1);
1185 			} else
1186 				node.team_ref_count.erase(teamRef);
1187 		}
1188 	}
1189 
1190 	// Cleanup add-on references
1191 
1192 	for (size_t index = 0; index < fDormantFlavors.size(); index++) {
1193 		dormant_add_on_flavor_info& flavorInfo = fDormantFlavors[index];
1194 
1195 		TeamCountMap::iterator instanceCount
1196 			= flavorInfo.team_instances_count.find(team);
1197 		if (instanceCount != flavorInfo.team_instances_count.end()) {
1198 			PRINT(1, "NodeManager::CleanupTeam: removing %" B_PRId32 " "
1199 				"instances from addon %" B_PRId32 ", flavor %" B_PRId32 "\n",
1200 				instanceCount->second, flavorInfo.add_on_id,
1201 				flavorInfo.flavor_id);
1202 
1203 			int32 count = flavorInfo.instances_count;
1204 			flavorInfo.instances_count -= instanceCount->second;
1205 			if (flavorInfo.instances_count <= 0) {
1206 				fDormantFlavors.erase(fDormantFlavors.begin() + index--);
1207 				BPrivate::media::notifications::FlavorsChanged(
1208 					flavorInfo.add_on_id, 0, count);
1209 			} else
1210 				flavorInfo.team_instances_count.erase(team);
1211 		}
1212 	}
1213 }
1214 
1215 
1216 status_t
LoadState()1217 NodeManager::LoadState()
1218 {
1219 	BAutolock _(this);
1220 	return fDefaultManager->LoadState();
1221 }
1222 
1223 status_t
SaveState()1224 NodeManager::SaveState()
1225 {
1226 	BAutolock _(this);
1227 	return fDefaultManager->SaveState(this);
1228 }
1229 
1230 
1231 void
Dump()1232 NodeManager::Dump()
1233 {
1234 	BAutolock _(this);
1235 
1236 	// for each addon-id, the add-on path map contains an entry_ref
1237 
1238 	printf("\nNodeManager: addon path map follows:\n");
1239 
1240 	for (PathMap::iterator iterator = fPathMap.begin();
1241 			iterator != fPathMap.end(); iterator++) {
1242 		BPath path(&iterator->second);
1243 		printf(" addon-id %" B_PRId32 ", path \"%s\"\n", iterator->first,
1244 			path.InitCheck() == B_OK ? path.Path() : "INVALID");
1245 	}
1246 
1247 	printf("NodeManager: list end\n\n");
1248 
1249 	// for each node-id, the registered node map contians information about
1250 	// source of the node, users, etc.
1251 
1252 	printf("NodeManager: registered nodes map follows:\n");
1253 	for (NodeMap::iterator iterator = fNodeMap.begin();
1254 			iterator != fNodeMap.end(); iterator++) {
1255 		registered_node& node = iterator->second;
1256 
1257 		printf("  node-id %" B_PRId32 ", addon-id %" B_PRId32 ", addon-flavor-"
1258 			"id %" B_PRId32 ", port %" B_PRId32 ", creator %" B_PRId32 ", "
1259 			"team %" B_PRId32 ", kinds %#08" B_PRIx64 ", name \"%s\", "
1260 			"ref_count %" B_PRId32 "\n", node.node_id, node.add_on_id,
1261 			node.flavor_id, node.port, node.creator, node.containing_team,
1262 			node.kinds, node.name, node.ref_count);
1263 
1264 		printf("    teams (refcount): ");
1265 		for (TeamCountMap::iterator refsIterator = node.team_ref_count.begin();
1266 				refsIterator != node.team_ref_count.end(); refsIterator++) {
1267 			printf("%" B_PRId32 " (%" B_PRId32 "), ", refsIterator->first,
1268 				refsIterator->second);
1269 		}
1270 		printf("\n");
1271 
1272 		for (InputList::iterator inIterator = node.input_list.begin();
1273 				inIterator != node.input_list.end(); inIterator++) {
1274 			media_input& input = *inIterator;
1275 			printf("    media_input: node-id %" B_PRId32 ", node-port %"
1276 				B_PRId32 ", source-port %" B_PRId32 ", source-id  %" B_PRId32
1277 				", dest-port %" B_PRId32 ", dest-id %" B_PRId32 ", name "
1278 				"\"%s\"\n", input.node.node, input.node.port, input.source.port,
1279 				input.source.id, input.destination.port, input.destination.id,
1280 				input.name);
1281 		}
1282 		if (node.input_list.empty())
1283 			printf("    media_input: none\n");
1284 
1285 		for (OutputList::iterator outIterator = node.output_list.begin();
1286 				outIterator != node.output_list.end(); outIterator++) {
1287 			media_output& output = *outIterator;
1288 			printf("    media_output: node-id %" B_PRId32 ", node-port %"
1289 				B_PRId32 ", source-port %" B_PRId32 ", source-id  %" B_PRId32
1290 				", dest-port %" B_PRId32 ", dest-id %" B_PRId32 ", name "
1291 				"\"%s\"\n", output.node.node, output.node.port,
1292 				output.source.port, output.source.id, output.destination.port,
1293 				output.destination.id, output.name);
1294 		}
1295 		if (node.output_list.empty())
1296 			printf("    media_output: none\n");
1297 	}
1298 
1299 	printf("NodeManager: list end\n");
1300 	printf("\n");
1301 
1302 	// Dormant add-on flavors
1303 
1304 	printf("NodeManager: dormant flavor list follows:\n");
1305 
1306 	for (DormantFlavorList::iterator iterator = fDormantFlavors.begin();
1307 			iterator != fDormantFlavors.end(); iterator++) {
1308 		dormant_add_on_flavor_info& flavorInfo = *iterator;
1309 
1310 		printf("  addon-id %" B_PRId32 ", flavor-id %" B_PRId32 ", max "
1311 			"instances count %" B_PRId32 ", instances count %" B_PRId32 ", "
1312 			"info valid %s\n", flavorInfo.add_on_id, flavorInfo.flavor_id,
1313 			flavorInfo.max_instances_count, flavorInfo.instances_count,
1314 			flavorInfo.info_valid ? "yes" : "no");
1315 		printf("    teams (instances): ");
1316 		for (TeamCountMap::iterator countIterator
1317 					= flavorInfo.team_instances_count.begin();
1318 				countIterator != flavorInfo.team_instances_count.end();
1319 				countIterator++) {
1320 			printf("%" B_PRId32 " (%" B_PRId32 "), ", countIterator->first,
1321 				countIterator->second);
1322 		}
1323 		printf("\n");
1324 		if (!flavorInfo.info_valid)
1325 			continue;
1326 
1327 		printf("    addon-id %" B_PRId32 ", addon-flavor-id %" B_PRId32 ", "
1328 			"addon-name \"%s\"\n", flavorInfo.info.node_info.addon,
1329 			flavorInfo.info.node_info.flavor_id,
1330 			flavorInfo.info.node_info.name);
1331 		printf("    flavor-kinds %#08" B_PRIx64 ", flavor_flags %#08" B_PRIx32
1332 			", internal_id %" B_PRId32 ", possible_count %" B_PRId32 ", "
1333 			"in_format_count %" B_PRId32 ", out_format_count %" B_PRId32 "\n",
1334 			flavorInfo.info.kinds, flavorInfo.info.flavor_flags,
1335 			flavorInfo.info.internal_id, flavorInfo.info.possible_count,
1336 			flavorInfo.info.in_format_count, flavorInfo.info.out_format_count);
1337 		printf("    flavor-name \"%s\"\n", flavorInfo.info.name);
1338 		printf("    flavor-info \"%s\"\n", flavorInfo.info.info);
1339 	}
1340 	printf("NodeManager: list end\n");
1341 
1342 	fDefaultManager->Dump();
1343 }
1344 
1345 
1346 // #pragma mark - private methods
1347 
1348 
1349 status_t
_AcquireNodeReference(media_node_id id,team_id team)1350 NodeManager::_AcquireNodeReference(media_node_id id, team_id team)
1351 {
1352 	TRACE("NodeManager::_AcquireNodeReference enter: node %" B_PRId32 ", team "
1353 		"%" B_PRId32 "\n", id, team);
1354 
1355 	BAutolock _(this);
1356 
1357 	NodeMap::iterator found = fNodeMap.find(id);
1358 	if (found == fNodeMap.end()) {
1359 		ERROR("NodeManager::_AcquireNodeReference: node %" B_PRId32 " not "
1360 			"found\n", id);
1361 		return B_ERROR;
1362 	}
1363 
1364 	registered_node& node = found->second;
1365 
1366 	TeamCountMap::iterator teamRef = node.team_ref_count.find(team);
1367 	if (teamRef == node.team_ref_count.end()) {
1368 		// This is the team's first reference
1369 		try {
1370 			node.team_ref_count.insert(std::make_pair(team, 1));
1371 		} catch (std::bad_alloc& exception) {
1372 			return B_NO_MEMORY;
1373 		}
1374 	} else {
1375 		// Just increase its ref count
1376 		teamRef->second++;
1377 	}
1378 
1379 	node.ref_count++;
1380 
1381 	TRACE("NodeManager::_AcquireNodeReference leave: node %" B_PRId32 ", team "
1382 		"%" B_PRId32 ", ref %" B_PRId32 ", team ref %" B_PRId32 "\n", id, team,
1383 		node.ref_count, node.team_ref_count.find(team)->second);
1384 	return B_OK;
1385 }
1386 
1387 
1388 void
_NotifyTimeSource(registered_node & node)1389 NodeManager::_NotifyTimeSource(registered_node& node)
1390 {
1391 	team_id team = be_app->Team();
1392 	media_node timeSource;
1393 	// Ensure the timesource ensure still exists
1394 	if (GetCloneForID(node.timesource_id, team, &timeSource) != B_OK)
1395 		return;
1396 
1397 	media_node currentNode;
1398 	if (GetCloneForID(node.node_id, team,
1399 		&currentNode) == B_OK) {
1400 		timesource_remove_slave_node_command cmd;
1401 		cmd.node = currentNode;
1402 		// Notify slave node removal to owner timesource
1403 		SendToPort(timeSource.port, TIMESOURCE_REMOVE_SLAVE_NODE,
1404 			&cmd, sizeof(cmd));
1405 		ReleaseNode(timeSource, team);
1406 	}
1407 	ReleaseNode(currentNode, team);
1408 }
1409