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