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