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