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 ¤tNode) == 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