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