1 /* 2 * Copyright 2015 Dario Casalinuovo 3 * Copyright 2009-2012, Axel Dörfler, axeld@pinc-software.de. 4 * Copyright 2008 Maurice Kalinowski, haiku@kaldience.com 5 * 6 * All rights reserved. Distributed under the terms of the MIT License. 7 */ 8 9 /* 10 * Copyright (c) 2002-2006 Marcus Overhagen <Marcus@Overhagen.de> 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining 13 * a copy of this software and associated documentation files or portions 14 * thereof (the "Software"), to deal in the Software without restriction, 15 * including without limitation the rights to use, copy, modify, merge, 16 * publish, distribute, sublicense, and/or sell copies of the Software, 17 * and to permit persons to whom the Software is furnished to do so, subject 18 * to the following conditions: 19 * 20 * * Redistributions of source code must retain the above copyright notice, 21 * this list of conditions and the following disclaimer. 22 * 23 * * Redistributions in binary form must reproduce the above copyright notice 24 * in the binary, as well as this list of conditions and the following 25 * disclaimer in the documentation and/or other materials provided with 26 * the distribution. 27 * 28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 29 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 31 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 33 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 34 * THE SOFTWARE. 35 */ 36 37 38 /* to comply with the license above, do not remove the following line */ 39 char __dont_remove_copyright_from_binary[] = "Copyright (c) 2002-2006 Marcus " 40 "Overhagen <Marcus@Overhagen.de>"; 41 42 43 #include <MediaRoster.h> 44 45 #include <Application.h> 46 #include <Autolock.h> 47 #include <BufferConsumer.h> 48 #include <BufferProducer.h> 49 #include <Locker.h> 50 #include <Message.h> 51 #include <Messenger.h> 52 #include <MimeType.h> 53 #include <OS.h> 54 #include <ParameterWeb.h> 55 #include <Roster.h> 56 #include <StopWatch.h> 57 #include <String.h> 58 #include <TimeSource.h> 59 60 #include <new> 61 62 #include <AppMisc.h> 63 #include <DataExchange.h> 64 #include <debug.h> 65 #include <DormantNodeManager.h> 66 #include <MediaMisc.h> 67 #include <MediaRosterEx.h> 68 #include <Notifications.h> 69 #include <ServerInterface.h> 70 #include <SharedBufferList.h> 71 #include <TList.h> 72 73 #include "TimeSourceObjectManager.h" 74 75 76 namespace BPrivate { 77 namespace media { 78 79 80 struct RosterNotification { 81 BMessenger messenger; 82 int32 what; 83 }; 84 85 86 struct SyncedMessage { 87 BMessage* message; 88 }; 89 90 91 struct LocalNode { 92 LocalNode(BMediaNode* local_node) 93 : 94 node(local_node) {} 95 96 LocalNode() 97 : 98 node(NULL) {} 99 100 bool operator==(const LocalNode& a) 101 { 102 if (a.node == this->node) 103 return true; 104 return false; 105 } 106 107 BMediaNode* node; 108 }; 109 110 111 static bool sServerIsUp = false; 112 static List<RosterNotification> sNotificationList; 113 static BLocker sInitLocker("BMediaRoster::Roster locker"); 114 static List<LocalNode> sRegisteredNodes; 115 static List<SyncedMessage> sSyncedMessages; 116 117 118 class MediaRosterUndertaker { 119 public: 120 ~MediaRosterUndertaker() 121 { 122 BAutolock _(sInitLocker); 123 if (BMediaRoster::CurrentRoster() != NULL 124 && BMediaRoster::CurrentRoster()->Lock()) { 125 126 // Detect any forgotten node 127 if (sRegisteredNodes.CountItems() > 0) { 128 for (int32 i = 0; i < sRegisteredNodes.CountItems(); i++) { 129 LocalNode* node = NULL; 130 sRegisteredNodes.Get(i, &node); 131 if (node != NULL) { 132 ERROR("BMediaRoster: Node with ID %" B_PRId32 133 " was not released correctly\n", node->node->ID()); 134 } 135 } 136 } 137 138 if (be_app != NULL) 139 be_app->UnregisterLooper(BMediaRoster::CurrentRoster()); 140 141 BMediaRoster::CurrentRoster()->Quit(); 142 } 143 } 144 }; 145 146 147 static MediaRosterUndertaker sMediaRosterUndertaker; 148 149 } // namespace media 150 } // namespace BPrivate 151 152 using namespace BPrivate::media; 153 154 155 BMediaRosterEx::BMediaRosterEx(status_t* _error) 156 : 157 BMediaRoster(), 158 fLaunchNotification(false), 159 fAutoExit(false) 160 { 161 gDormantNodeManager = new DormantNodeManager(); 162 gTimeSourceObjectManager = new TimeSourceObjectManager(); 163 164 *_error = BuildConnections(); 165 166 InitRosterDataExchange(BMessenger(this, this)); 167 168 if (be_roster->StartWatching(BMessenger(this, this), 169 B_REQUEST_LAUNCHED | B_REQUEST_QUIT) != B_OK) { 170 *_error = B_ERROR; 171 } 172 sServerIsUp = BMediaRoster::IsRunning(); 173 } 174 175 176 void 177 BMediaRosterEx::Quit() 178 { 179 if (be_roster->StopWatching(BMessenger(this, this)) != B_OK) 180 TRACE("Can't unregister roster notifications"); 181 182 if (sNotificationList.CountItems() != 0) 183 sNotificationList.MakeEmpty(); 184 185 BMediaRoster::Quit(); 186 } 187 188 189 status_t 190 BMediaRosterEx::BuildConnections() 191 { 192 InitServerDataExchange(); 193 // register this application with the media server 194 server_register_app_request request; 195 server_register_app_reply reply; 196 request.team = BPrivate::current_team(); 197 request.messenger = BMessenger(NULL, this); 198 status_t status = QueryServer(SERVER_REGISTER_APP, &request, 199 sizeof(request), &reply, sizeof(reply)); 200 if (status != B_OK) 201 return B_MEDIA_SYSTEM_FAILURE; 202 203 return B_OK; 204 } 205 206 207 BMediaRosterEx::~BMediaRosterEx() 208 { 209 CALLED(); 210 211 delete gTimeSourceObjectManager; 212 delete gDormantNodeManager; 213 214 // unregister this application with the media server 215 server_unregister_app_request request; 216 server_unregister_app_reply reply; 217 request.team = BPrivate::current_team(); 218 QueryServer(SERVER_UNREGISTER_APP, &request, sizeof(request), &reply, 219 sizeof(reply)); 220 221 BPrivate::SharedBufferList::Invalidate(); 222 } 223 224 225 void 226 BMediaRosterEx::RegisterLocalNode(BMediaNode* node) 227 { 228 sRegisteredNodes.Insert(LocalNode(node)); 229 } 230 231 232 void 233 BMediaRosterEx::UnregisterLocalNode(BMediaNode* node) 234 { 235 int32 index = sRegisteredNodes.Find(LocalNode(node)); 236 if (index != -1) 237 sRegisteredNodes.Remove(index); 238 } 239 240 241 void 242 BMediaRosterEx::EnableLaunchNotification(bool enable, bool autoExit) 243 { 244 // NOTE: in theory, we should personalize it depending on each 245 // request, but we are using it just in launch/shutdown_media_server, 246 // so we are enough safe to don't care about that. 247 fLaunchNotification = enable; 248 fAutoExit = autoExit; 249 } 250 251 252 status_t 253 BMediaRosterEx::SaveNodeConfiguration(BMediaNode* node) 254 { 255 int32 flavorID; 256 BMediaAddOn* addon = node->AddOn(&flavorID); 257 if (addon == NULL) { 258 // NOTE: This node could have been created by an application, 259 // it does not mean there is an error. 260 // TODO: this check incorrectly triggers on BeOS R5 BT848 node 261 TRACE("BMediaRosterEx::SaveNodeConfiguration node %" B_PRId32 " not " 262 "instantiated from BMediaAddOn!\n", node->ID()); 263 return B_ERROR; 264 } 265 266 media_addon_id addonID = addon->AddonID(); 267 268 // TODO: fix this 269 printf("### BMediaRosterEx::SaveNodeConfiguration should save addon-id " 270 "%" B_PRId32 ", flavor-id %" B_PRId32 " config NOW!\n", addonID, 271 flavorID); 272 return B_OK; 273 } 274 275 276 status_t 277 BMediaRosterEx::LoadNodeConfiguration(media_addon_id addonID, int32 flavorID, 278 BMessage *_msg) 279 { 280 // TODO: fix this 281 _msg->MakeEmpty(); // to be fully R5 compliant 282 printf("### BMediaRosterEx::LoadNodeConfiguration should load addon-id " 283 "%" B_PRId32 ", flavor-id %" B_PRId32 " config NOW!\n", addonID, 284 flavorID); 285 return B_OK; 286 } 287 288 289 status_t 290 BMediaRosterEx::IncrementAddonFlavorInstancesCount(media_addon_id addonID, 291 int32 flavorID) 292 { 293 server_change_flavor_instances_count_request request; 294 server_change_flavor_instances_count_reply reply; 295 296 request.add_on_id = addonID; 297 request.flavor_id = flavorID; 298 request.delta = 1; 299 request.team = BPrivate::current_team(); 300 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT, &request, 301 sizeof(request), &reply, sizeof(reply)); 302 } 303 304 305 status_t 306 BMediaRosterEx::DecrementAddonFlavorInstancesCount(media_addon_id addonID, 307 int32 flavorID) 308 { 309 server_change_flavor_instances_count_request request; 310 server_change_flavor_instances_count_reply reply; 311 312 request.add_on_id = addonID; 313 request.flavor_id = flavorID; 314 request.delta = -1; 315 request.team = BPrivate::current_team(); 316 return QueryServer(SERVER_CHANGE_FLAVOR_INSTANCES_COUNT, &request, 317 sizeof(request), &reply, sizeof(reply)); 318 } 319 320 321 status_t 322 BMediaRosterEx::ReleaseNodeAll(const media_node& node) 323 { 324 CALLED(); 325 if (IS_INVALID_NODE(node)) 326 return B_MEDIA_BAD_NODE; 327 328 if (node.kind & NODE_KIND_NO_REFCOUNTING) 329 return B_OK; 330 331 server_release_node_request request; 332 server_release_node_reply reply; 333 status_t rv; 334 335 request.node = node; 336 request.team = BPrivate::current_team(); 337 338 TRACE("BMediaRoster::ReleaseNodeAll, node %" B_PRId32 ", port %" B_PRId32 339 ", team %" B_PRId32 "\n", 340 node.node, node.port, BPrivate::current_team()); 341 342 rv = QueryServer(SERVER_RELEASE_NODE_ALL, &request, sizeof(request), &reply, 343 sizeof(reply)); 344 if (rv != B_OK) { 345 ERROR("BMediaRoster::ReleaseNodeAll failed to query media_server, " 346 "retrying local, node %" B_PRId32 ", port %" 347 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port, 348 BPrivate::current_team()); 349 node_final_release_command command; 350 rv = SendToPort(node.port, NODE_FINAL_RELEASE, &command, 351 sizeof(command)); 352 if (rv != B_OK) { 353 ERROR("BMediaRoster::ReleaseNodeAll FAILED, node %" B_PRId32 ", port %" 354 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port, 355 BPrivate::current_team()); 356 } 357 } 358 return rv; 359 } 360 361 362 status_t 363 BMediaRosterEx::SetNodeCreator(media_node_id node, team_id creator) 364 { 365 server_set_node_creator_request request; 366 server_set_node_creator_reply reply; 367 368 request.node = node; 369 request.creator = creator; 370 return QueryServer(SERVER_SET_NODE_CREATOR, &request, sizeof(request), 371 &reply, sizeof(reply)); 372 } 373 374 375 status_t 376 BMediaRosterEx::GetNode(node_type type, media_node* out_node, 377 int32* out_input_id, BString* out_input_name) 378 { 379 if (out_node == NULL) 380 return B_BAD_VALUE; 381 382 server_get_node_request request; 383 server_get_node_reply reply; 384 status_t rv; 385 386 request.type = type; 387 request.team = BPrivate::current_team(); 388 rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply, 389 sizeof(reply)); 390 if (rv != B_OK) 391 return rv; 392 393 *out_node = reply.node; 394 if (out_input_id) 395 *out_input_id = reply.input_id; 396 if (out_input_name) 397 *out_input_name = reply.input_name; 398 return rv; 399 } 400 401 402 status_t 403 BMediaRosterEx::SetNode(node_type type, const media_node* node, 404 const dormant_node_info* info, const media_input* input) 405 { 406 server_set_node_request request; 407 server_set_node_reply reply; 408 409 request.type = type; 410 request.use_node = node != NULL; 411 if (node != NULL) 412 request.node = *node; 413 request.use_dni = info != NULL; 414 if (info != NULL) 415 request.dni = *info; 416 request.use_input = input != NULL; 417 if (input != NULL) 418 request.input = *input; 419 420 return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply, 421 sizeof(reply)); 422 } 423 424 425 status_t 426 BMediaRosterEx::GetAllOutputs(const media_node& node, List<media_output>* list) 427 { 428 int32 cookie; 429 status_t rv; 430 status_t result; 431 432 PRINT(4, "BMediaRosterEx::GetAllOutputs() node %" B_PRId32 ", port %" 433 B_PRId32 "\n", node.node, node.port); 434 435 if (!(node.kind & B_BUFFER_PRODUCER)) { 436 ERROR("BMediaRosterEx::GetAllOutputs: node %" B_PRId32 " is not a " 437 "B_BUFFER_PRODUCER\n", node.node); 438 return B_MEDIA_BAD_NODE; 439 } 440 441 result = B_OK; 442 cookie = 0; 443 list->MakeEmpty(); 444 for (;;) { 445 producer_get_next_output_request request; 446 producer_get_next_output_reply reply; 447 request.cookie = cookie; 448 rv = QueryPort(node.port, PRODUCER_GET_NEXT_OUTPUT, &request, 449 sizeof(request), &reply, sizeof(reply)); 450 if (rv != B_OK) 451 break; 452 cookie = reply.cookie; 453 if (!list->Insert(reply.output)) { 454 ERROR("GetAllOutputs: list->Insert failed\n"); 455 result = B_ERROR; 456 } 457 #if DEBUG >= 3 458 PRINT(3," next cookie %" B_PRId32 ", ", cookie); 459 PRINT_OUTPUT("output ", reply.output); 460 #endif 461 } 462 463 producer_dispose_output_cookie_request request; 464 producer_dispose_output_cookie_reply reply; 465 QueryPort(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &request, 466 sizeof(request), &reply, sizeof(reply)); 467 468 return result; 469 } 470 471 472 status_t 473 BMediaRosterEx::GetAllOutputs(BBufferProducer* node, List<media_output>* list) 474 { 475 int32 cookie; 476 status_t result; 477 478 PRINT(4, "BMediaRosterEx::GetAllOutputs() (by pointer) node %" B_PRId32 479 ", port %" B_PRId32 "\n", node->ID(), node->ControlPort()); 480 481 result = B_OK; 482 cookie = 0; 483 list->MakeEmpty(); 484 for (;;) { 485 media_output output; 486 if (B_OK != node->GetNextOutput(&cookie, &output)) 487 break; 488 if (!list->Insert(output)) { 489 ERROR("GetAllOutputs: list->Insert failed\n"); 490 result = B_ERROR; 491 } 492 #if DEBUG >= 3 493 PRINT(3," next cookie %" B_PRId32 ", ", cookie); 494 PRINT_OUTPUT("output ", output); 495 #endif 496 } 497 node->DisposeOutputCookie(cookie); 498 return result; 499 } 500 501 502 status_t 503 BMediaRosterEx::GetAllInputs(const media_node& node, List<media_input>* list) 504 { 505 int32 cookie; 506 status_t rv; 507 status_t result; 508 509 PRINT(4, "BMediaRosterEx::GetAllInputs() node %" B_PRId32 ", port %" 510 B_PRId32 "\n", node.node, node.port); 511 512 if (!(node.kind & B_BUFFER_CONSUMER)) { 513 ERROR("BMediaRosterEx::GetAllInputs: node %" B_PRId32 " is not a " 514 "B_BUFFER_CONSUMER\n", node.node); 515 return B_MEDIA_BAD_NODE; 516 } 517 518 result = B_OK; 519 cookie = 0; 520 list->MakeEmpty(); 521 for (;;) { 522 consumer_get_next_input_request request; 523 consumer_get_next_input_reply reply; 524 request.cookie = cookie; 525 rv = QueryPort(node.port, CONSUMER_GET_NEXT_INPUT, &request, 526 sizeof(request), &reply, sizeof(reply)); 527 if (rv != B_OK) 528 break; 529 cookie = reply.cookie; 530 if (!list->Insert(reply.input)) { 531 ERROR("GetAllInputs: list->Insert failed\n"); 532 result = B_ERROR; 533 } 534 #if DEBUG >= 3 535 PRINT(3," next cookie %" B_PRId32 ", ", cookie); 536 PRINT_OUTPUT("input ", reply.input); 537 #endif 538 } 539 540 consumer_dispose_input_cookie_request request; 541 consumer_dispose_input_cookie_reply reply; 542 QueryPort(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &request, 543 sizeof(request), &reply, sizeof(reply)); 544 545 return result; 546 } 547 548 549 status_t 550 BMediaRosterEx::GetAllInputs(BBufferConsumer* node, List<media_input>* list) 551 { 552 int32 cookie; 553 status_t result; 554 555 PRINT(4, "BMediaRosterEx::GetAllInputs() (by pointer) node %" B_PRId32 556 ", port %" B_PRId32 "\n", node->ID(), node->ControlPort()); 557 558 result = B_OK; 559 cookie = 0; 560 list->MakeEmpty(); 561 for (;;) { 562 media_input input; 563 if (B_OK != node->GetNextInput(&cookie, &input)) 564 break; 565 if (!list->Insert(input)) { 566 ERROR("GetAllInputs: list->Insert failed\n"); 567 result = B_ERROR; 568 } 569 #if DEBUG >= 3 570 PRINT(3," next cookie %" B_PRId32 ", ", cookie); 571 PRINT_INPUT("input ", input); 572 #endif 573 } 574 node->DisposeInputCookie(cookie); 575 return result; 576 } 577 578 579 status_t 580 BMediaRosterEx::PublishOutputs(const media_node& node, List<media_output>* list) 581 { 582 server_publish_outputs_request request; 583 server_publish_outputs_reply reply; 584 media_output* output; 585 media_output* outputs; 586 int32 count; 587 status_t rv; 588 589 count = list->CountItems(); 590 TRACE("PublishOutputs: publishing %" B_PRId32 "\n", count); 591 592 request.node = node; 593 request.count = count; 594 if (count > MAX_OUTPUTS) { 595 void *start_addr; 596 size_t size; 597 size = ROUND_UP_TO_PAGE(count * sizeof(media_output)); 598 request.area = create_area("publish outputs", &start_addr, 599 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 600 if (request.area < B_OK) { 601 ERROR("PublishOutputs: failed to create area, %#" B_PRIx32 "\n", 602 request.area); 603 return (status_t)request.area; 604 } 605 outputs = static_cast<media_output *>(start_addr); 606 } else { 607 request.area = -1; 608 outputs = request.outputs; 609 } 610 TRACE("PublishOutputs: area %" B_PRId32 "\n", request.area); 611 612 int i; 613 for (i = 0, list->Rewind(); list->GetNext(&output); i++) { 614 ASSERT(i < count); 615 outputs[i] = *output; 616 } 617 618 rv = QueryServer(SERVER_PUBLISH_OUTPUTS, &request, sizeof(request), 619 &reply, sizeof(reply)); 620 621 if (request.area != -1) 622 delete_area(request.area); 623 624 return rv; 625 } 626 627 628 status_t 629 BMediaRosterEx::PublishInputs(const media_node& node, List<media_input>* list) 630 { 631 server_publish_inputs_request request; 632 server_publish_inputs_reply reply; 633 media_input* input; 634 media_input* inputs; 635 int32 count; 636 status_t rv; 637 638 count = list->CountItems(); 639 TRACE("PublishInputs: publishing %" B_PRId32 "\n", count); 640 641 request.node = node; 642 request.count = count; 643 if (count > MAX_INPUTS) { 644 void* start_addr; 645 size_t size; 646 size = ROUND_UP_TO_PAGE(count * sizeof(media_input)); 647 request.area = create_area("publish inputs", &start_addr, 648 B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 649 if (request.area < B_OK) { 650 ERROR("PublishInputs: failed to create area, %#" B_PRIx32 "\n", 651 request.area); 652 return (status_t)request.area; 653 } 654 inputs = static_cast<media_input *>(start_addr); 655 } else { 656 request.area = -1; 657 inputs = request.inputs; 658 } 659 TRACE("PublishInputs: area %" B_PRId32 "\n", request.area); 660 661 int i; 662 for (i = 0, list->Rewind(); list->GetNext(&input); i++) { 663 ASSERT(i < count); 664 inputs[i] = *input; 665 } 666 667 rv = QueryServer(SERVER_PUBLISH_INPUTS, &request, sizeof(request), 668 &reply, sizeof(reply)); 669 670 if (request.area != -1) 671 delete_area(request.area); 672 673 return rv; 674 } 675 676 677 BTimeSource* 678 BMediaRosterEx::MakeTimeSourceObject(media_node_id timeSourceID) 679 { 680 media_node clone; 681 status_t status = GetNodeFor(timeSourceID, &clone); 682 if (status != B_OK) { 683 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed: %s\n", 684 strerror(status)); 685 return NULL; 686 } 687 688 BTimeSource* source = gTimeSourceObjectManager->GetTimeSource(clone); 689 if (source == NULL) { 690 ERROR("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n"); 691 return NULL; 692 } 693 694 // TODO: release? 695 ReleaseNode(clone); 696 697 return source; 698 } 699 700 701 // #pragma mark - public BMediaRoster 702 703 704 status_t 705 BMediaRoster::GetVideoInput(media_node* _node) 706 { 707 CALLED(); 708 return MediaRosterEx(this)->GetNode(VIDEO_INPUT, _node); 709 } 710 711 712 status_t 713 BMediaRoster::GetAudioInput(media_node* _node) 714 { 715 CALLED(); 716 return MediaRosterEx(this)->GetNode(AUDIO_INPUT, _node); 717 } 718 719 720 status_t 721 BMediaRoster::GetVideoOutput(media_node* _node) 722 { 723 CALLED(); 724 return MediaRosterEx(this)->GetNode(VIDEO_OUTPUT, _node); 725 } 726 727 728 status_t 729 BMediaRoster::GetAudioMixer(media_node* _node) 730 { 731 CALLED(); 732 return MediaRosterEx(this)->GetNode(AUDIO_MIXER, _node); 733 } 734 735 736 status_t 737 BMediaRoster::GetAudioOutput(media_node* _node) 738 { 739 CALLED(); 740 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT, _node); 741 } 742 743 744 status_t 745 BMediaRoster::GetAudioOutput(media_node* _node, int32* _inputID, 746 BString* _inputName) 747 { 748 CALLED(); 749 return MediaRosterEx(this)->GetNode(AUDIO_OUTPUT_EX, _node, _inputID, 750 _inputName); 751 } 752 753 754 status_t 755 BMediaRoster::GetTimeSource(media_node* _node) 756 { 757 CALLED(); 758 status_t rv; 759 760 // TODO: need to do this in a nicer way. 761 762 rv = MediaRosterEx(this)->GetNode(TIME_SOURCE, _node); 763 if (rv != B_OK) 764 return rv; 765 766 // We don't do reference counting for timesources, that's why we 767 // release the node immediately. 768 ReleaseNode(*_node); 769 770 // we need to remember to not use this node with server side reference counting 771 _node->kind |= NODE_KIND_NO_REFCOUNTING; 772 return B_OK; 773 } 774 775 776 status_t 777 BMediaRoster::SetVideoInput(const media_node& producer) 778 { 779 CALLED(); 780 return MediaRosterEx(this)->SetNode(VIDEO_INPUT, &producer); 781 } 782 783 784 status_t 785 BMediaRoster::SetVideoInput(const dormant_node_info& producer) 786 { 787 CALLED(); 788 return MediaRosterEx(this)->SetNode(VIDEO_INPUT, NULL, &producer); 789 } 790 791 792 status_t 793 BMediaRoster::SetAudioInput(const media_node& producer) 794 { 795 CALLED(); 796 return MediaRosterEx(this)->SetNode(AUDIO_INPUT, &producer); 797 } 798 799 800 status_t 801 BMediaRoster::SetAudioInput(const dormant_node_info& producer) 802 { 803 CALLED(); 804 return MediaRosterEx(this)->SetNode(AUDIO_INPUT, NULL, &producer); 805 } 806 807 808 status_t 809 BMediaRoster::SetVideoOutput(const media_node& consumer) 810 { 811 CALLED(); 812 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, &consumer); 813 } 814 815 816 status_t 817 BMediaRoster::SetVideoOutput(const dormant_node_info& consumer) 818 { 819 CALLED(); 820 return MediaRosterEx(this)->SetNode(VIDEO_OUTPUT, NULL, &consumer); 821 } 822 823 824 status_t 825 BMediaRoster::SetAudioOutput(const media_node& consumer) 826 { 827 CALLED(); 828 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, &consumer); 829 } 830 831 832 status_t 833 BMediaRoster::SetAudioOutput(const media_input& input) 834 { 835 CALLED(); 836 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, NULL, &input); 837 } 838 839 840 status_t 841 BMediaRoster::SetAudioOutput(const dormant_node_info& consumer) 842 { 843 CALLED(); 844 return MediaRosterEx(this)->SetNode(AUDIO_OUTPUT, NULL, &consumer); 845 } 846 847 848 status_t 849 BMediaRoster::GetNodeFor(media_node_id node, media_node* clone) 850 { 851 CALLED(); 852 if (clone == NULL) 853 return B_BAD_VALUE; 854 if (IS_INVALID_NODEID(node)) 855 return B_MEDIA_BAD_NODE; 856 857 server_get_node_for_request request; 858 server_get_node_for_reply reply; 859 status_t rv; 860 861 request.node_id = node; 862 request.team = BPrivate::current_team(); 863 864 rv = QueryServer(SERVER_GET_NODE_FOR, &request, sizeof(request), &reply, 865 sizeof(reply)); 866 if (rv != B_OK) 867 return rv; 868 869 *clone = reply.clone; 870 return B_OK; 871 } 872 873 874 status_t 875 BMediaRoster::GetSystemTimeSource(media_node* clone) 876 { 877 CALLED(); 878 status_t rv; 879 880 // TODO: need to do this in a nicer way. 881 882 rv = MediaRosterEx(this)->GetNode(SYSTEM_TIME_SOURCE, clone); 883 if (rv != B_OK) 884 return rv; 885 886 // We don't do reference counting for timesources, that's why we 887 // release the node immediately. 888 ReleaseNode(*clone); 889 890 // we need to remember to not use this node with server side reference 891 // counting 892 clone->kind |= NODE_KIND_NO_REFCOUNTING; 893 894 return B_OK; 895 } 896 897 898 status_t 899 BMediaRoster::ReleaseNode(const media_node& node) 900 { 901 CALLED(); 902 if (IS_INVALID_NODE(node)) 903 return B_MEDIA_BAD_NODE; 904 905 if (node.kind & NODE_KIND_NO_REFCOUNTING) { 906 TRACE("BMediaRoster::ReleaseNode, trying to release reference " 907 "counting disabled timesource, node %" B_PRId32 ", port %" B_PRId32 908 ", team %" B_PRId32 "\n", node.node, node.port, 909 BPrivate::current_team()); 910 return B_OK; 911 } 912 913 server_release_node_request request; 914 server_release_node_reply reply; 915 status_t rv; 916 917 request.node = node; 918 request.team = BPrivate::current_team(); 919 920 TRACE("BMediaRoster::ReleaseNode, node %" B_PRId32 ", port %" B_PRId32 921 ", team %" B_PRId32 "\n", node.node, node.port, 922 BPrivate::current_team()); 923 924 rv = QueryServer(SERVER_RELEASE_NODE, &request, sizeof(request), &reply, 925 sizeof(reply)); 926 if (rv != B_OK) { 927 ERROR("BMediaRoster::ReleaseNode FAILED, node %" B_PRId32 ", port %" 928 B_PRId32 ", team %" B_PRId32 "!\n", node.node, node.port, 929 BPrivate::current_team()); 930 } 931 return rv; 932 } 933 934 935 BTimeSource* 936 BMediaRoster::MakeTimeSourceFor(const media_node& forNode) 937 { 938 // MakeTimeSourceFor() returns a BTimeSource object 939 // corresponding to the specified node's time source. 940 941 CALLED(); 942 943 if (IS_SYSTEM_TIMESOURCE(forNode)) { 944 // special handling for the system time source 945 TRACE("BMediaRoster::MakeTimeSourceFor, asked for system time " 946 "source\n"); 947 return MediaRosterEx(this)->MakeTimeSourceObject( 948 NODE_SYSTEM_TIMESOURCE_ID); 949 } 950 951 if (IS_INVALID_NODE(forNode)) { 952 ERROR("BMediaRoster::MakeTimeSourceFor: for_node invalid, node %" 953 B_PRId32 ", port %" B_PRId32 ", kinds 0x%" B_PRIx32 "\n", 954 forNode.node, forNode.port, forNode.kind); 955 return NULL; 956 } 957 958 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32 " enter\n", 959 forNode.node); 960 961 node_get_timesource_request request; 962 node_get_timesource_reply reply; 963 BTimeSource *source; 964 status_t rv; 965 966 // ask the node to get it's current timesource id 967 rv = QueryPort(forNode.port, NODE_GET_TIMESOURCE, &request, 968 sizeof(request), &reply, sizeof(reply)); 969 if (rv != B_OK) { 970 ERROR("BMediaRoster::MakeTimeSourceFor: request failed\n"); 971 return NULL; 972 } 973 974 source = MediaRosterEx(this)->MakeTimeSourceObject(reply.timesource_id); 975 976 TRACE("BMediaRoster::MakeTimeSourceFor: node %" B_PRId32 " leave\n", 977 forNode.node); 978 979 return source; 980 } 981 982 983 status_t 984 BMediaRoster::Connect(const media_source& from, const media_destination& to, 985 media_format* _format, media_output* _output, media_input* _input) 986 { 987 return BMediaRoster::Connect(from, to, _format, _output, _input, 0); 988 } 989 990 991 status_t 992 BMediaRoster::Connect(const media_source& from, const media_destination& to, 993 media_format* io_format, media_output* out_output, media_input* out_input, 994 uint32 in_flags, void* _reserved) 995 { 996 CALLED(); 997 if (io_format == NULL || out_output == NULL || out_input == NULL) 998 return B_BAD_VALUE; 999 if (IS_INVALID_SOURCE(from)) { 1000 ERROR("BMediaRoster::Connect: media_source invalid\n"); 1001 return B_MEDIA_BAD_SOURCE; 1002 } 1003 if (IS_INVALID_DESTINATION(to)) { 1004 ERROR("BMediaRoster::Connect: media_destination invalid\n"); 1005 return B_MEDIA_BAD_DESTINATION; 1006 } 1007 1008 status_t rv; 1009 1010 // find the output and input nodes 1011 // TODO: isn't there a easier way? 1012 media_node sourcenode; 1013 media_node destnode; 1014 rv = GetNodeFor(NodeIDFor(from.port), &sourcenode); 1015 if (rv != B_OK) { 1016 ERROR("BMediaRoster::Connect: Can't find source node for port %" 1017 B_PRId32 "\n", from.port); 1018 return B_MEDIA_BAD_SOURCE; 1019 } 1020 ReleaseNode(sourcenode); 1021 rv = GetNodeFor(NodeIDFor(to.port), &destnode); 1022 if (rv != B_OK) { 1023 ERROR("BMediaRoster::Connect: Can't find destination node for port " 1024 "%" B_PRId32 "\n", to.port); 1025 return B_MEDIA_BAD_DESTINATION; 1026 } 1027 ReleaseNode(destnode); 1028 1029 if (!(sourcenode.kind & B_BUFFER_PRODUCER)) { 1030 ERROR("BMediaRoster::Connect: source node %" B_PRId32 " is not a " 1031 "B_BUFFER_PRODUCER\n", sourcenode.node); 1032 return B_MEDIA_BAD_SOURCE; 1033 } 1034 if (!(destnode.kind & B_BUFFER_CONSUMER)) { 1035 ERROR("BMediaRoster::Connect: destination node %" B_PRId32 " is not a " 1036 "B_BUFFER_CONSUMER\n", destnode.node); 1037 return B_MEDIA_BAD_DESTINATION; 1038 } 1039 1040 producer_format_proposal_request request1; 1041 producer_format_proposal_reply reply1; 1042 1043 PRINT_FORMAT("BMediaRoster::Connect calling " 1044 "BBufferProducer::FormatProposal with format ", *io_format); 1045 1046 // BBufferProducer::FormatProposal 1047 request1.output = from; 1048 request1.format = *io_format; 1049 rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1, 1050 sizeof(request1), &reply1, sizeof(reply1)); 1051 if (rv != B_OK) { 1052 ERROR("BMediaRoster::Connect: aborted after " 1053 "BBufferProducer::FormatProposal, status = %#" B_PRIx32 "\n",rv); 1054 return rv; 1055 } 1056 // reply1.format now contains the format proposed by the producer 1057 1058 consumer_accept_format_request request2; 1059 consumer_accept_format_reply reply2; 1060 1061 PRINT_FORMAT("BMediaRoster::Connect calling " 1062 "BBufferConsumer::AcceptFormat with format ", reply1.format); 1063 1064 // BBufferConsumer::AcceptFormat 1065 request2.dest = to; 1066 request2.format = reply1.format; 1067 rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2, 1068 sizeof(request2), &reply2, sizeof(reply2)); 1069 if (rv != B_OK) { 1070 ERROR("BMediaRoster::Connect: aborted after " 1071 "BBufferConsumer::AcceptFormat, status = %#" B_PRIx32 "\n",rv); 1072 return rv; 1073 } 1074 // reply2.format now contains the format accepted by the consumer 1075 1076 // BBufferProducer::PrepareToConnect 1077 producer_prepare_to_connect_request request3; 1078 producer_prepare_to_connect_reply reply3; 1079 1080 PRINT_FORMAT("BMediaRoster::Connect calling " 1081 "BBufferProducer::PrepareToConnect with format", reply2.format); 1082 1083 request3.source = from; 1084 request3.destination = to; 1085 request3.format = reply2.format; 1086 strcpy(request3.name, "XXX some default name"); // TODO: fix this 1087 rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3, 1088 sizeof(request3), &reply3, sizeof(reply3)); 1089 if (rv != B_OK) { 1090 ERROR("BMediaRoster::Connect: aborted after " 1091 "BBufferProducer::PrepareToConnect, status = %#" B_PRIx32 "\n", rv); 1092 return rv; 1093 } 1094 // reply3.format is still our pretty media format 1095 // reply3.out_source the real source to be used for the connection 1096 // reply3.name the name BBufferConsumer::Connected will see in the 1097 // outInput->name argument 1098 1099 // BBufferConsumer::Connected 1100 consumer_connected_request request4; 1101 consumer_connected_reply reply4; 1102 status_t con_status; 1103 1104 PRINT_FORMAT("BMediaRoster::Connect calling BBufferConsumer::Connected() " 1105 "with format ", reply3.format); 1106 1107 request4.input.node = destnode; 1108 request4.input.source = reply3.out_source; 1109 request4.input.destination = to; 1110 request4.input.format = reply3.format; 1111 strcpy(request4.input.name, reply3.name); 1112 1113 con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4, 1114 sizeof(request4), &reply4, sizeof(reply4)); 1115 if (con_status != B_OK) { 1116 ERROR("BMediaRoster::Connect: aborting after " 1117 "BBufferConsumer::Connected, status = %#" B_PRIx32 "\n", 1118 con_status); 1119 // we do NOT return here! 1120 } 1121 // con_status contains the status code to be supplied to 1122 // BBufferProducer::Connect's status argument 1123 // reply4.input contains the media_input that describes the connection 1124 // from the consumer point of view 1125 1126 // BBufferProducer::Connect 1127 producer_connect_request request5; 1128 producer_connect_reply reply5; 1129 1130 PRINT_FORMAT("BMediaRoster::Connect calling BBufferProducer::Connect with " 1131 "format ", reply4.input.format); 1132 1133 request5.error = con_status; 1134 request5.source = reply3.out_source; 1135 request5.destination = reply4.input.destination; 1136 request5.format = reply4.input.format; 1137 strcpy(request5.name, reply4.input.name); 1138 rv = QueryPort(reply4.input.source.port, PRODUCER_CONNECT, &request5, 1139 sizeof(request5), &reply5, sizeof(reply5)); 1140 if (con_status != B_OK) { 1141 ERROR("BMediaRoster::Connect: aborted\n"); 1142 return con_status; 1143 } 1144 if (rv != B_OK) { 1145 ERROR("BMediaRoster::Connect: aborted after BBufferProducer::Connect()" 1146 ", status = %#" B_PRIx32 "\n", rv); 1147 return rv; 1148 } 1149 // reply5.name contains the name assigned to the connection by the producer 1150 1151 // initilize connection info 1152 *io_format = reply4.input.format; 1153 *out_input = reply4.input; 1154 out_output->node = sourcenode; 1155 out_output->source = reply4.input.source; 1156 out_output->destination = reply4.input.destination; 1157 out_output->format = reply4.input.format; 1158 strcpy(out_output->name, reply5.name); 1159 1160 // the connection is now made 1161 PRINT_FORMAT(" format", *io_format); 1162 PRINT_INPUT(" input", *out_input); 1163 PRINT_OUTPUT(" output", *out_output); 1164 1165 // TODO: register connection with server 1166 // TODO: we should just send a notification, instead of republishing all 1167 // endpoints 1168 List<media_output> outlist; 1169 List<media_input> inlist; 1170 if (MediaRosterEx(this)->GetAllOutputs(out_output->node , &outlist) == B_OK) 1171 MediaRosterEx(this)->PublishOutputs(out_output->node , &outlist); 1172 if (MediaRosterEx(this)->GetAllInputs(out_input->node , &inlist) == B_OK) 1173 MediaRosterEx(this)->PublishInputs(out_input->node, &inlist); 1174 1175 // TODO: if (mute) BBufferProducer::EnableOutput(false) 1176 if (in_flags & B_CONNECT_MUTED) { 1177 } 1178 1179 // send a notification 1180 BPrivate::media::notifications::ConnectionMade(*out_input, *out_output, 1181 *io_format); 1182 1183 return B_OK; 1184 }; 1185 1186 1187 status_t 1188 BMediaRoster::Disconnect(media_node_id source_nodeid, 1189 const media_source& source, media_node_id destination_nodeid, 1190 const media_destination& destination) 1191 { 1192 CALLED(); 1193 if (IS_INVALID_NODEID(source_nodeid)) { 1194 ERROR("BMediaRoster::Disconnect: source media_node_id invalid\n"); 1195 return B_MEDIA_BAD_SOURCE; 1196 } 1197 if (IS_INVALID_NODEID(destination_nodeid)) { 1198 ERROR("BMediaRoster::Disconnect: destination media_node_id invalid\n"); 1199 return B_MEDIA_BAD_DESTINATION; 1200 } 1201 if (IS_INVALID_SOURCE(source)) { 1202 ERROR("BMediaRoster::Disconnect: media_source invalid\n"); 1203 return B_MEDIA_BAD_SOURCE; 1204 } 1205 if (IS_INVALID_DESTINATION(destination)) { 1206 ERROR("BMediaRoster::Disconnect: media_destination invalid\n"); 1207 return B_MEDIA_BAD_DESTINATION; 1208 } 1209 1210 producer_disconnect_request request2; 1211 producer_disconnect_reply reply2; 1212 consumer_disconnected_request request1; 1213 consumer_disconnected_reply reply1; 1214 status_t rv1, rv2; 1215 1216 // TODO: we should ask the server if this connection really exists 1217 1218 request1.source = source; 1219 request1.destination = destination; 1220 request2.source = source; 1221 request2.destination = destination; 1222 1223 rv1 = QueryPort(source.port, PRODUCER_DISCONNECT, &request1, 1224 sizeof(request1), &reply1, sizeof(reply1)); 1225 rv2 = QueryPort(destination.port, CONSUMER_DISCONNECTED, &request2, 1226 sizeof(request2), &reply2, sizeof(reply2)); 1227 1228 // TODO: unregister connection with server 1229 // TODO: we should just send a notification, instead of republishing all 1230 // endpoints 1231 List<media_output> outlist; 1232 List<media_input> inlist; 1233 media_node sourcenode; 1234 media_node destnode; 1235 if (GetNodeFor(source_nodeid, &sourcenode) == B_OK) { 1236 if (!(sourcenode.kind & B_BUFFER_PRODUCER)) { 1237 ERROR("BMediaRoster::Disconnect: source_nodeid %" B_PRId32 1238 " is not a B_BUFFER_PRODUCER\n", source_nodeid); 1239 } 1240 if (MediaRosterEx(this)->GetAllOutputs(sourcenode , &outlist) == B_OK) 1241 MediaRosterEx(this)->PublishOutputs(sourcenode , &outlist); 1242 ReleaseNode(sourcenode); 1243 } else { 1244 ERROR("BMediaRoster::Disconnect: GetNodeFor source_nodeid %" B_PRId32 1245 " failed\n", source_nodeid); 1246 } 1247 if (GetNodeFor(destination_nodeid, &destnode) == B_OK) { 1248 if (!(destnode.kind & B_BUFFER_CONSUMER)) { 1249 ERROR("BMediaRoster::Disconnect: destination_nodeid %" B_PRId32 1250 " is not a B_BUFFER_CONSUMER\n", destination_nodeid); 1251 } 1252 if (MediaRosterEx(this)->GetAllInputs(destnode , &inlist) == B_OK) 1253 MediaRosterEx(this)->PublishInputs(destnode, &inlist); 1254 ReleaseNode(destnode); 1255 } else { 1256 ERROR("BMediaRoster::Disconnect: GetNodeFor destination_nodeid %" 1257 B_PRId32 " failed\n", destination_nodeid); 1258 } 1259 1260 // send a notification 1261 BPrivate::media::notifications::ConnectionBroken(source, destination); 1262 1263 return rv1 != B_OK || rv2 != B_OK ? B_ERROR : B_OK; 1264 } 1265 1266 1267 status_t 1268 BMediaRoster::Disconnect(const media_output& output, const media_input& input) 1269 { 1270 if (IS_INVALID_NODEID(output.node.node)) { 1271 printf("BMediaRoster::Disconnect: output.node.node %" B_PRId32 1272 " invalid\n", output.node.node); 1273 return B_MEDIA_BAD_SOURCE; 1274 } 1275 if (IS_INVALID_NODEID(input.node.node)) { 1276 printf("BMediaRoster::Disconnect: input.node.node %" B_PRId32 1277 " invalid\n", input.node.node); 1278 return B_MEDIA_BAD_DESTINATION; 1279 } 1280 if (!(output.node.kind & B_BUFFER_PRODUCER)) { 1281 printf("BMediaRoster::Disconnect: output.node.kind 0x%" B_PRIx32 1282 " is no B_BUFFER_PRODUCER\n", output.node.kind); 1283 return B_MEDIA_BAD_SOURCE; 1284 } 1285 if (!(input.node.kind & B_BUFFER_CONSUMER)) { 1286 printf("BMediaRoster::Disconnect: input.node.kind 0x%" B_PRIx32 1287 " is no B_BUFFER_PRODUCER\n", input.node.kind); 1288 return B_MEDIA_BAD_DESTINATION; 1289 } 1290 if (input.source.port != output.source.port) { 1291 printf("BMediaRoster::Disconnect: input.source.port %" B_PRId32 1292 " doesn't match output.source.port %" B_PRId32 "\n", 1293 input.source.port, output.source.port); 1294 return B_MEDIA_BAD_SOURCE; 1295 } 1296 if (input.source.id != output.source.id) { 1297 printf("BMediaRoster::Disconnect: input.source.id %" B_PRId32 1298 " doesn't match output.source.id %" B_PRId32 "\n", input.source.id, 1299 output.source.id); 1300 return B_MEDIA_BAD_SOURCE; 1301 } 1302 if (input.destination.port != output.destination.port) { 1303 printf("BMediaRoster::Disconnect: input.destination.port %" B_PRId32 1304 " doesn't match output.destination.port %" B_PRId32 "\n", 1305 input.destination.port, output.destination.port); 1306 return B_MEDIA_BAD_DESTINATION; 1307 } 1308 if (input.destination.id != output.destination.id) { 1309 printf("BMediaRoster::Disconnect: input.destination.id %" B_PRId32 1310 " doesn't match output.destination.id %" B_PRId32 "\n", 1311 input.destination.id, output.destination.id); 1312 return B_MEDIA_BAD_DESTINATION; 1313 } 1314 1315 return Disconnect(output.node.node, output.source, input.node.node, 1316 input.destination); 1317 } 1318 1319 1320 status_t 1321 BMediaRoster::StartNode(const media_node& node, bigtime_t atPerformanceTime) 1322 { 1323 CALLED(); 1324 if (node.node <= 0) 1325 return B_MEDIA_BAD_NODE; 1326 1327 TRACE("BMediaRoster::StartNode, node %" B_PRId32 ", at perf %" B_PRId64 1328 "\n", node.node, atPerformanceTime); 1329 1330 node_start_command command; 1331 command.performance_time = atPerformanceTime; 1332 1333 return SendToPort(node.port, NODE_START, &command, sizeof(command)); 1334 } 1335 1336 1337 status_t 1338 BMediaRoster::StopNode(const media_node& node, bigtime_t atPerformanceTime, 1339 bool immediate) 1340 { 1341 CALLED(); 1342 if (IS_INVALID_NODE(node)) 1343 return B_MEDIA_BAD_NODE; 1344 1345 TRACE("BMediaRoster::StopNode, node %" B_PRId32 ", at perf %" B_PRId64 1346 " %s\n", node.node, atPerformanceTime, immediate ? "NOW" : ""); 1347 1348 node_stop_command command; 1349 command.performance_time = atPerformanceTime; 1350 command.immediate = immediate; 1351 1352 return SendToPort(node.port, NODE_STOP, &command, sizeof(command)); 1353 } 1354 1355 1356 status_t 1357 BMediaRoster::SeekNode(const media_node& node, bigtime_t toMediaTime, 1358 bigtime_t atPerformanceTime) 1359 { 1360 CALLED(); 1361 if (IS_INVALID_NODE(node)) 1362 return B_MEDIA_BAD_NODE; 1363 1364 TRACE("BMediaRoster::SeekNode, node %" B_PRId32 ", at perf %" B_PRId64 1365 ", to perf %" B_PRId64 "\n", node.node, atPerformanceTime, toMediaTime); 1366 1367 node_seek_command command; 1368 command.media_time = toMediaTime; 1369 command.performance_time = atPerformanceTime; 1370 1371 return SendToPort(node.port, NODE_SEEK, &command, sizeof(command)); 1372 } 1373 1374 1375 status_t 1376 BMediaRoster::StartTimeSource(const media_node& node, bigtime_t atRealTime) 1377 { 1378 CALLED(); 1379 if (IS_SYSTEM_TIMESOURCE(node)) { 1380 // TODO: debug this 1381 //ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is system timesource\n", node.node); 1382 return B_OK; 1383 } 1384 // if (IS_SHADOW_TIMESOURCE(node)) { 1385 // // TODO: debug this 1386 // ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " is shadow timesource\n", node.node); 1387 // return B_OK; 1388 // } 1389 if (IS_INVALID_NODE(node)) { 1390 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 " invalid\n", 1391 node.node); 1392 return B_MEDIA_BAD_NODE; 1393 } 1394 if ((node.kind & B_TIME_SOURCE) == 0) { 1395 ERROR("BMediaRoster::StartTimeSource node %" B_PRId32 1396 " is no timesource\n", node.node); 1397 return B_MEDIA_BAD_NODE; 1398 } 1399 1400 TRACE("BMediaRoster::StartTimeSource, node %" B_PRId32 ", at real %" 1401 B_PRId64 "\n", node.node, atRealTime); 1402 1403 BTimeSource::time_source_op_info msg; 1404 msg.op = BTimeSource::B_TIMESOURCE_START; 1405 msg.real_time = atRealTime; 1406 1407 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 1408 } 1409 1410 1411 status_t 1412 BMediaRoster::StopTimeSource(const media_node& node, bigtime_t atRealTime, 1413 bool immediate) 1414 { 1415 CALLED(); 1416 if (IS_SYSTEM_TIMESOURCE(node)) { 1417 // TODO: debug this 1418 //ERROR("BMediaRoster::StopTimeSource node %ld is system timesource\n", node.node); 1419 return B_OK; 1420 } 1421 // if (IS_SHADOW_TIMESOURCE(node)) { 1422 // // TODO: debug this 1423 // ERROR("BMediaRoster::StopTimeSource node %ld is shadow timesource\n", node.node); 1424 // return B_OK; 1425 // } 1426 if (IS_INVALID_NODE(node)) { 1427 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32 " invalid\n", 1428 node.node); 1429 return B_MEDIA_BAD_NODE; 1430 } 1431 if ((node.kind & B_TIME_SOURCE) == 0) { 1432 ERROR("BMediaRoster::StopTimeSource node %" B_PRId32 " is no " 1433 "timesource\n", node.node); 1434 return B_MEDIA_BAD_NODE; 1435 } 1436 1437 TRACE("BMediaRoster::StopTimeSource, node %" B_PRId32 ", at real %" B_PRId64 1438 " %s\n", node.node, atRealTime, immediate ? "NOW" : ""); 1439 1440 BTimeSource::time_source_op_info msg; 1441 msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY 1442 : BTimeSource::B_TIMESOURCE_STOP; 1443 msg.real_time = atRealTime; 1444 1445 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 1446 } 1447 1448 1449 status_t 1450 BMediaRoster::SeekTimeSource(const media_node& node, 1451 bigtime_t toPerformanceTime, bigtime_t atRealTime) 1452 { 1453 CALLED(); 1454 if (IS_SYSTEM_TIMESOURCE(node)) { 1455 // TODO: debug this 1456 // ERROR("BMediaRoster::SeekTimeSource node %ld is system timesource\n", node.node); 1457 // you can't seek the system time source, but 1458 // returning B_ERROR would break StampTV 1459 return B_OK; 1460 } 1461 // if (IS_SHADOW_TIMESOURCE(node)) { 1462 // // TODO: debug this 1463 // ERROR("BMediaRoster::SeekTimeSource node %ld is shadow timesource\n", node.node); 1464 // return B_OK; 1465 // } 1466 if (IS_INVALID_NODE(node)) { 1467 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32 " invalid\n", 1468 node.node); 1469 return B_MEDIA_BAD_NODE; 1470 } 1471 if ((node.kind & B_TIME_SOURCE) == 0) { 1472 ERROR("BMediaRoster::SeekTimeSource node %" B_PRId32 1473 " is no timesource\n", node.node); 1474 return B_MEDIA_BAD_NODE; 1475 } 1476 1477 TRACE("BMediaRoster::SeekTimeSource, node %" B_PRId32 ", at real %" B_PRId64 1478 ", to perf %" B_PRId64 "\n", node.node, atRealTime, toPerformanceTime); 1479 1480 BTimeSource::time_source_op_info msg; 1481 msg.op = BTimeSource::B_TIMESOURCE_SEEK; 1482 msg.real_time = atRealTime; 1483 msg.performance_time = toPerformanceTime; 1484 1485 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 1486 } 1487 1488 1489 status_t 1490 BMediaRoster::SyncToNode(const media_node& node, bigtime_t atTime, 1491 bigtime_t timeout) 1492 { 1493 TRACE("BMediaRoster::SyncToNode, node %" B_PRId32 ", at real %" B_PRId64 1494 ", at timeout %" B_PRId64 "\n", node.node, atTime, timeout); 1495 if (IS_INVALID_NODE(node)) 1496 return B_MEDIA_BAD_NODE; 1497 1498 port_id waitPort = create_port(1, "SyncToNode wait port"); 1499 if (waitPort < B_OK) 1500 return waitPort; 1501 1502 node_sync_to_request request; 1503 node_sync_to_reply reply; 1504 request.performance_time = atTime; 1505 request.port = waitPort; 1506 1507 status_t status = QueryPort(node.port, NODE_SYNC_TO, &request, 1508 sizeof(request), &reply, sizeof(reply)); 1509 1510 if (status == B_OK) { 1511 ssize_t readSize = read_port_etc(waitPort, NULL, &status, 1512 sizeof(status), B_TIMEOUT, timeout); 1513 if (readSize < 0) 1514 status = readSize; 1515 } 1516 close_port(waitPort); 1517 delete_port(waitPort); 1518 return status; 1519 } 1520 1521 1522 status_t 1523 BMediaRoster::SetRunModeNode(const media_node& node, BMediaNode::run_mode mode) 1524 { 1525 TRACE("BMediaRoster::SetRunModeNode, node %" B_PRId32 ", mode %d\n", 1526 node.node, mode); 1527 if (IS_INVALID_NODE(node)) 1528 return B_MEDIA_BAD_NODE; 1529 1530 node_set_run_mode_command msg; 1531 msg.mode = mode; 1532 1533 return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg)); 1534 } 1535 1536 1537 status_t 1538 BMediaRoster::PrerollNode(const media_node& node) 1539 { 1540 CALLED(); 1541 if (IS_INVALID_NODE(node)) 1542 return B_MEDIA_BAD_NODE; 1543 1544 char dummy; 1545 return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy)); 1546 } 1547 1548 1549 status_t 1550 BMediaRoster::RollNode(const media_node& node, bigtime_t startPerformance, 1551 bigtime_t stopPerformance, bigtime_t atMediaTime) 1552 { 1553 CALLED(); 1554 if (IS_INVALID_NODE(node)) 1555 return B_MEDIA_BAD_NODE; 1556 1557 TRACE("BMediaRoster::RollNode, node %" B_PRId32 ", at start perf %" 1558 B_PRId64 ", at stop perf %" B_PRId64 ", at media time %" 1559 B_PRId64 "\n", node.node, startPerformance, 1560 stopPerformance, atMediaTime); 1561 1562 node_roll_command command; 1563 command.start_performance_time = startPerformance; 1564 command.stop_performance_time = stopPerformance; 1565 command.seek_media_time = atMediaTime; 1566 1567 return write_port(node.port, NODE_ROLL, &command, sizeof(command)); 1568 } 1569 1570 1571 status_t 1572 BMediaRoster::SetProducerRunModeDelay(const media_node& node, 1573 bigtime_t delay, BMediaNode::run_mode mode) 1574 { 1575 TRACE("BMediaRoster::SetProducerRunModeDelay, node %" B_PRId32 ", delay %" 1576 B_PRId64 ", mode %d\n", node.node, delay, mode); 1577 if (IS_INVALID_NODE(node)) 1578 return B_MEDIA_BAD_NODE; 1579 if ((node.kind & B_BUFFER_PRODUCER) == 0) 1580 return B_MEDIA_BAD_NODE; 1581 1582 producer_set_run_mode_delay_command command; 1583 command.mode = mode; 1584 command.delay = delay; 1585 1586 return SendToPort(node.port, PRODUCER_SET_RUN_MODE_DELAY, &command, 1587 sizeof(command)); 1588 } 1589 1590 1591 status_t 1592 BMediaRoster::SetProducerRate(const media_node& producer, int32 numer, 1593 int32 denom) 1594 { 1595 CALLED(); 1596 if (IS_INVALID_NODE(producer)) 1597 return B_MEDIA_BAD_NODE; 1598 if ((producer.kind & B_BUFFER_PRODUCER) == 0) 1599 return B_MEDIA_BAD_NODE; 1600 1601 producer_set_play_rate_request request; 1602 request.numer = numer; 1603 request.denom = denom; 1604 status_t status = write_port(producer.node, PRODUCER_SET_PLAY_RATE, 1605 &request, sizeof(request)); 1606 if (status != B_OK) 1607 return status; 1608 1609 producer_set_play_rate_reply reply; 1610 int32 code; 1611 status = read_port(request.reply_port, &code, &reply, sizeof(reply)); 1612 1613 return status < B_OK ? status : reply.result; 1614 } 1615 1616 1617 /*! Nodes will have available inputs/outputs as long as they are capable 1618 of accepting more connections. The node may create an additional 1619 output or input as the currently available is taken into usage. 1620 */ 1621 status_t 1622 BMediaRoster::GetLiveNodeInfo(const media_node& node, 1623 live_node_info* out_live_info) 1624 { 1625 CALLED(); 1626 if (out_live_info == NULL) 1627 return B_BAD_VALUE; 1628 if (IS_INVALID_NODE(node)) 1629 return B_MEDIA_BAD_NODE; 1630 1631 server_get_live_node_info_request request; 1632 server_get_live_node_info_reply reply; 1633 status_t rv; 1634 1635 request.node = node; 1636 1637 rv = QueryServer(SERVER_GET_LIVE_NODE_INFO, &request, sizeof(request), 1638 &reply, sizeof(reply)); 1639 if (rv != B_OK) 1640 return rv; 1641 1642 *out_live_info = reply.live_info; 1643 return B_OK; 1644 } 1645 1646 1647 status_t 1648 BMediaRoster::GetLiveNodes(live_node_info* liveNodes, int32* _totalCount, 1649 const media_format* hasInput, const media_format* hasOutput, 1650 const char* name, uint64 nodeKinds) 1651 { 1652 CALLED(); 1653 if (liveNodes == NULL || _totalCount == NULL || *_totalCount <= 0) 1654 return B_BAD_VALUE; 1655 1656 // TODO: we also support the wildcard search as GetDormantNodes does. 1657 // This needs to be documented 1658 1659 server_get_live_nodes_request request; 1660 request.team = BPrivate::current_team(); 1661 1662 request.max_count = *_totalCount; 1663 request.has_input = hasInput != NULL; 1664 if (hasInput != NULL) { 1665 // TODO: we should not make a flat copy of media_format 1666 request.input_format = *hasInput; 1667 } 1668 request.has_output = hasOutput != NULL; 1669 if (hasOutput != NULL) { 1670 // TODO: we should not make a flat copy of media_format 1671 request.output_format = *hasOutput; 1672 } 1673 request.has_name = name != NULL; 1674 if (name != NULL) 1675 strlcpy(request.name, name, sizeof(request.name)); 1676 request.require_kinds = nodeKinds; 1677 1678 server_get_live_nodes_reply reply; 1679 status_t status = QueryServer(SERVER_GET_LIVE_NODES, &request, 1680 sizeof(request), &reply, sizeof(reply)); 1681 if (status != B_OK) { 1682 ERROR("BMediaRoster::GetLiveNodes failed querying server: %s\n", 1683 strerror(status)); 1684 *_totalCount = 0; 1685 return status; 1686 } 1687 1688 const live_node_info* info; 1689 if (reply.area >= 0) 1690 info = (live_node_info*)reply.address; 1691 else 1692 info = reply.live_info; 1693 1694 for (int32 i = 0; i < reply.count; i++) 1695 liveNodes[i] = info[i]; 1696 1697 if (reply.area >= 0) 1698 delete_area(reply.area); 1699 1700 *_totalCount = reply.count; 1701 return B_OK; 1702 } 1703 1704 1705 status_t 1706 BMediaRoster::GetFreeInputsFor(const media_node& node, 1707 media_input * out_free_inputs, int32 buf_num_inputs, 1708 int32 * out_total_count, media_type filter_type) 1709 { 1710 CALLED(); 1711 if (IS_INVALID_NODE(node)) { 1712 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32 ", port %" 1713 B_PRId32 " invalid\n", node.node, node.port); 1714 return B_MEDIA_BAD_NODE; 1715 } 1716 if ((node.kind & B_BUFFER_CONSUMER) == 0) { 1717 ERROR("BMediaRoster::GetFreeInputsFor: node %" B_PRId32 ", port %" 1718 B_PRId32 " is not a consumer\n", node.node, node.port); 1719 return B_MEDIA_BAD_NODE; 1720 } 1721 if (out_free_inputs == NULL || out_total_count == NULL) 1722 return B_BAD_VALUE; 1723 1724 List<media_input> list; 1725 media_input *input; 1726 status_t rv; 1727 1728 *out_total_count = 0; 1729 1730 rv = MediaRosterEx(this)->GetAllInputs(node, &list); 1731 if (B_OK != rv) 1732 return rv; 1733 1734 PRINT(4, "BMediaRoster::GetFreeInputsFor node %" B_PRId32 ", max %" B_PRId32 1735 ", filter-type %" B_PRId32 "\n", node.node, buf_num_inputs, 1736 filter_type); 1737 1738 int32 i; 1739 for (i = 0, list.Rewind(); list.GetNext(&input);) { 1740 if (filter_type != B_MEDIA_UNKNOWN_TYPE 1741 && filter_type != input->format.type) { 1742 // media_type used, but doesn't match 1743 continue; 1744 } 1745 if (input->source != media_source::null) { 1746 // consumer source already connected 1747 continue; 1748 } 1749 1750 out_free_inputs[i] = *input; 1751 *out_total_count += 1; 1752 buf_num_inputs -= 1; 1753 #if DEBUG >= 3 1754 PRINT_OUTPUT(" input", out_free_inputs[i]); 1755 #endif 1756 if (buf_num_inputs == 0) 1757 break; 1758 i++; 1759 } 1760 1761 MediaRosterEx(this)->PublishInputs(node, &list); 1762 return B_OK; 1763 } 1764 1765 1766 status_t 1767 BMediaRoster::GetConnectedInputsFor(const media_node& node, 1768 media_input* out_active_inputs, int32 buf_num_inputs, 1769 int32* out_total_count) 1770 { 1771 CALLED(); 1772 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0) 1773 return B_MEDIA_BAD_NODE; 1774 if (out_active_inputs == NULL || out_total_count == NULL) 1775 return B_BAD_VALUE; 1776 1777 List<media_input> list; 1778 media_input *input; 1779 status_t rv; 1780 1781 *out_total_count = 0; 1782 1783 rv = MediaRosterEx(this)->GetAllInputs(node, &list); 1784 if (B_OK != rv) 1785 return rv; 1786 1787 PRINT(4, "BMediaRoster::GetConnectedInputsFor node %" B_PRId32 ", max %" 1788 B_PRId32 "\n", node.node, buf_num_inputs); 1789 1790 int32 i; 1791 for (i = 0, list.Rewind(); list.GetNext(&input);) { 1792 if (input->source == media_source::null) 1793 continue; // consumer source not connected 1794 out_active_inputs[i] = *input; 1795 *out_total_count += 1; 1796 buf_num_inputs -= 1; 1797 #if DEBUG >= 3 1798 PRINT_OUTPUT(" input ", out_active_inputs[i]); 1799 #endif 1800 if (buf_num_inputs == 0) 1801 break; 1802 i++; 1803 } 1804 1805 MediaRosterEx(this)->PublishInputs(node, &list); 1806 return B_OK; 1807 } 1808 1809 1810 status_t 1811 BMediaRoster::GetAllInputsFor(const media_node& node, media_input* out_inputs, 1812 int32 buf_num_inputs, int32* out_total_count) 1813 { 1814 CALLED(); 1815 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_CONSUMER) == 0) 1816 return B_MEDIA_BAD_NODE; 1817 if (out_inputs == NULL || out_total_count == NULL) 1818 return B_BAD_VALUE; 1819 1820 List<media_input> list; 1821 media_input *input; 1822 status_t rv; 1823 1824 *out_total_count = 0; 1825 1826 rv = MediaRosterEx(this)->GetAllInputs(node, &list); 1827 if (B_OK != rv) 1828 return rv; 1829 1830 PRINT(4, "BMediaRoster::GetAllInputsFor node %" B_PRId32 ", max %" B_PRId32 1831 "\n", node.node, buf_num_inputs); 1832 1833 int32 i; 1834 for (i = 0, list.Rewind(); list.GetNext(&input); i++) { 1835 out_inputs[i] = *input; 1836 *out_total_count += 1; 1837 buf_num_inputs -= 1; 1838 #if DEBUG >= 3 1839 PRINT_OUTPUT(" input ", out_inputs[i]); 1840 #endif 1841 if (buf_num_inputs == 0) 1842 break; 1843 } 1844 1845 MediaRosterEx(this)->PublishInputs(node, &list); 1846 return B_OK; 1847 } 1848 1849 1850 status_t 1851 BMediaRoster::GetFreeOutputsFor(const media_node& node, 1852 media_output* out_free_outputs, int32 buf_num_outputs, 1853 int32* out_total_count, media_type filter_type) 1854 { 1855 CALLED(); 1856 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0) 1857 return B_MEDIA_BAD_NODE; 1858 if (out_free_outputs == NULL || out_total_count == NULL) 1859 return B_BAD_VALUE; 1860 1861 List<media_output> list; 1862 media_output *output; 1863 status_t rv; 1864 1865 *out_total_count = 0; 1866 1867 rv = MediaRosterEx(this)->GetAllOutputs(node, &list); 1868 if (B_OK != rv) 1869 return rv; 1870 1871 PRINT(4, "BMediaRoster::GetFreeOutputsFor node %" B_PRId32 ", max %" 1872 B_PRId32 ", filter-type %" B_PRId32 "\n", node.node, buf_num_outputs, 1873 filter_type); 1874 1875 int32 i; 1876 for (i = 0, list.Rewind(); list.GetNext(&output);) { 1877 if (filter_type != B_MEDIA_UNKNOWN_TYPE 1878 && filter_type != output->format.type) { 1879 // media_type used, but doesn't match 1880 continue; 1881 } 1882 if (output->destination != media_destination::null) { 1883 // producer destination already connected 1884 continue; 1885 } 1886 1887 out_free_outputs[i] = *output; 1888 *out_total_count += 1; 1889 buf_num_outputs -= 1; 1890 #if DEBUG >= 3 1891 PRINT_OUTPUT(" output ", out_free_outputs[i]); 1892 #endif 1893 if (buf_num_outputs == 0) 1894 break; 1895 i++; 1896 } 1897 1898 MediaRosterEx(this)->PublishOutputs(node, &list); 1899 return B_OK; 1900 } 1901 1902 1903 status_t 1904 BMediaRoster::GetConnectedOutputsFor(const media_node& node, 1905 media_output* out_active_outputs, int32 buf_num_outputs, 1906 int32* out_total_count) 1907 { 1908 CALLED(); 1909 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0) 1910 return B_MEDIA_BAD_NODE; 1911 if (out_active_outputs == NULL || out_total_count == NULL) 1912 return B_BAD_VALUE; 1913 1914 List<media_output> list; 1915 media_output *output; 1916 status_t rv; 1917 1918 *out_total_count = 0; 1919 1920 rv = MediaRosterEx(this)->GetAllOutputs(node, &list); 1921 if (B_OK != rv) 1922 return rv; 1923 1924 PRINT(4, "BMediaRoster::GetConnectedOutputsFor node %" B_PRId32 ", max %" 1925 B_PRId32 "\n", node.node, buf_num_outputs); 1926 1927 int32 i; 1928 for (i = 0, list.Rewind(); list.GetNext(&output);) { 1929 if (output->destination == media_destination::null) { 1930 // producer destination not connected 1931 continue; 1932 } 1933 out_active_outputs[i] = *output; 1934 *out_total_count += 1; 1935 buf_num_outputs -= 1; 1936 #if DEBUG >= 3 1937 PRINT_OUTPUT(" output ", out_active_outputs[i]); 1938 #endif 1939 if (buf_num_outputs == 0) 1940 break; 1941 i++; 1942 } 1943 1944 MediaRosterEx(this)->PublishOutputs(node, &list); 1945 return B_OK; 1946 } 1947 1948 1949 status_t 1950 BMediaRoster::GetAllOutputsFor(const media_node& node, 1951 media_output* out_outputs, int32 buf_num_outputs, int32* out_total_count) 1952 { 1953 CALLED(); 1954 if (IS_INVALID_NODE(node) || (node.kind & B_BUFFER_PRODUCER) == 0) 1955 return B_MEDIA_BAD_NODE; 1956 if (out_outputs == NULL || out_total_count == NULL) 1957 return B_BAD_VALUE; 1958 1959 List<media_output> list; 1960 media_output *output; 1961 status_t rv; 1962 1963 *out_total_count = 0; 1964 1965 rv = MediaRosterEx(this)->GetAllOutputs(node, &list); 1966 if (B_OK != rv) 1967 return rv; 1968 1969 PRINT(4, "BMediaRoster::GetAllOutputsFor node %" B_PRId32 ", max %" B_PRId32 1970 "\n", node.node, buf_num_outputs); 1971 1972 int32 i; 1973 for (i = 0, list.Rewind(); list.GetNext(&output); i++) { 1974 out_outputs[i] = *output; 1975 *out_total_count += 1; 1976 buf_num_outputs -= 1; 1977 #if DEBUG >= 3 1978 PRINT_OUTPUT(" output ", out_outputs[i]); 1979 #endif 1980 if (buf_num_outputs == 0) 1981 break; 1982 } 1983 1984 MediaRosterEx(this)->PublishOutputs(node, &list); 1985 return B_OK; 1986 } 1987 1988 1989 status_t 1990 BMediaRoster::StartWatching(const BMessenger& where) 1991 { 1992 CALLED(); 1993 if (!where.IsValid()) { 1994 ERROR("BMediaRoster::StartWatching: messenger invalid!\n"); 1995 return B_BAD_VALUE; 1996 } 1997 return BPrivate::media::notifications::Register(where, media_node::null, 1998 B_MEDIA_WILDCARD); 1999 } 2000 2001 2002 status_t 2003 BMediaRoster::StartWatching(const BMessenger & where, int32 notificationType) 2004 { 2005 CALLED(); 2006 if (!where.IsValid()) { 2007 ERROR("BMediaRoster::StartWatching: messenger invalid!\n"); 2008 return B_BAD_VALUE; 2009 } 2010 if (!BPrivate::media::notifications::IsValidNotificationRequest(false, 2011 notificationType)) { 2012 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n"); 2013 return B_BAD_VALUE; 2014 } 2015 2016 // NOTE: we support only explicitly B_MEDIA_SERVER_STARTED/QUIT 2017 // notifications. This should be cleared in documentation. 2018 2019 return BPrivate::media::notifications::Register(where, media_node::null, 2020 notificationType); 2021 } 2022 2023 2024 status_t 2025 BMediaRoster::StartWatching(const BMessenger& where, const media_node& node, 2026 int32 notificationType) 2027 { 2028 CALLED(); 2029 if (!where.IsValid()) { 2030 ERROR("BMediaRoster::StartWatching: messenger invalid!\n"); 2031 return B_BAD_VALUE; 2032 } 2033 if (IS_INVALID_NODE(node)) { 2034 ERROR("BMediaRoster::StartWatching: node invalid!\n"); 2035 return B_MEDIA_BAD_NODE; 2036 } 2037 if (!BPrivate::media::notifications::IsValidNotificationRequest(true, 2038 notificationType)) { 2039 ERROR("BMediaRoster::StartWatching: notificationType invalid!\n"); 2040 return B_BAD_VALUE; 2041 } 2042 return BPrivate::media::notifications::Register(where, node, 2043 notificationType); 2044 } 2045 2046 2047 status_t 2048 BMediaRoster::StopWatching(const BMessenger& where) 2049 { 2050 CALLED(); 2051 // messenger may already be invalid, so we don't check this 2052 return BPrivate::media::notifications::Unregister(where, media_node::null, 2053 B_MEDIA_WILDCARD); 2054 } 2055 2056 2057 status_t 2058 BMediaRoster::StopWatching(const BMessenger& where, int32 notificationType) 2059 { 2060 CALLED(); 2061 // messenger may already be invalid, so we don't check this 2062 if (!BPrivate::media::notifications::IsValidNotificationRequest(false, 2063 notificationType)) { 2064 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n"); 2065 return B_BAD_VALUE; 2066 } 2067 return BPrivate::media::notifications::Unregister(where, media_node::null, 2068 notificationType); 2069 } 2070 2071 2072 status_t 2073 BMediaRoster::StopWatching(const BMessenger& where, const media_node& node, 2074 int32 notificationType) 2075 { 2076 CALLED(); 2077 // messenger may already be invalid, so we don't check this 2078 if (IS_INVALID_NODE(node)) { 2079 ERROR("BMediaRoster::StopWatching: node invalid!\n"); 2080 return B_MEDIA_BAD_NODE; 2081 } 2082 if (!BPrivate::media::notifications::IsValidNotificationRequest(true, 2083 notificationType)) { 2084 ERROR("BMediaRoster::StopWatching: notificationType invalid!\n"); 2085 return B_BAD_VALUE; 2086 } 2087 return BPrivate::media::notifications::Unregister(where, node, 2088 notificationType); 2089 } 2090 2091 2092 status_t 2093 BMediaRoster::RegisterNode(BMediaNode* node) 2094 { 2095 CALLED(); 2096 // addon-id = -1 (unused), addon-flavor-id = 0 (unused, too) 2097 return MediaRosterEx(this)->RegisterNode(node, -1, 0); 2098 } 2099 2100 2101 status_t 2102 BMediaRosterEx::RegisterNode(BMediaNode* node, media_addon_id addOnID, 2103 int32 flavorID) 2104 { 2105 CALLED(); 2106 if (node == NULL) 2107 return B_BAD_VALUE; 2108 2109 // some sanity check 2110 // I'm not sure if the media kit warrants to call BMediaNode::AddOn() here. 2111 // Perhaps we don't need it. 2112 DEBUG_ONLY( 2113 int32 testFlavorID; 2114 BMediaAddOn* addon = node->AddOn(&testFlavorID); 2115 2116 ASSERT(addOnID == (addon != NULL ? addon->AddonID() : -1)); 2117 // ASSERT(flavorID == testFlavorID); 2118 ); 2119 2120 server_register_node_request request; 2121 server_register_node_reply reply; 2122 2123 request.add_on_id = addOnID; 2124 request.flavor_id = flavorID; 2125 strcpy(request.name, node->Name()); 2126 request.kinds = node->Kinds(); 2127 request.port = node->ControlPort(); 2128 request.team = BPrivate::current_team(); 2129 request.timesource_id = node->fTimeSourceID; 2130 2131 TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port " 2132 "%" B_PRId32 ", kinds 0x%" B_PRIx64 ", team %" B_PRId32 ", name '%s'\n", 2133 request.port, request.kinds, request.team, request.name); 2134 2135 status_t status = QueryServer(SERVER_REGISTER_NODE, &request, 2136 sizeof(request), &reply, sizeof(reply)); 2137 if (status != B_OK) { 2138 ERROR("BMediaRoster::RegisterNode: failed to register node %s: %s\n", 2139 node->Name(), strerror(status)); 2140 return status; 2141 } 2142 2143 TRACE("BMediaRoster::RegisterNode: QueryServer SERVER_REGISTER_NODE " 2144 "finished\n"); 2145 2146 // we are a friend class of BMediaNode and initialize this member variable 2147 node->fNodeID = reply.node_id; 2148 ASSERT(reply.node_id == node->Node().node); 2149 ASSERT(reply.node_id == node->ID()); 2150 2151 // call the callback 2152 node->NodeRegistered(); 2153 2154 TRACE("BMediaRoster::RegisterNode: NodeRegistered callback finished\n"); 2155 2156 // if the BMediaNode also inherits from BTimeSource, we need to call 2157 // BTimeSource::FinishCreate() 2158 if ((node->Kinds() & B_TIME_SOURCE) != 0) { 2159 if (BTimeSource* timeSource = dynamic_cast<BTimeSource*>(node)) 2160 timeSource->FinishCreate(); 2161 } 2162 2163 TRACE("BMediaRoster::RegisterNode: publishing inputs/outputs\n"); 2164 2165 // register existing inputs and outputs with the 2166 // media_server, this allows GetLiveNodes() to work 2167 // with created, but unconnected nodes. 2168 // The node control loop might not be running, or might deadlock 2169 // if we send a message and wait for a reply here. 2170 // We have a pointer to the node, and thus call the functions directly 2171 2172 if ((node->Kinds() & B_BUFFER_PRODUCER) != 0) { 2173 if (BBufferProducer* producer = dynamic_cast<BBufferProducer*>(node)) { 2174 List<media_output> list; 2175 if (GetAllOutputs(producer, &list) == B_OK) 2176 PublishOutputs(node->Node(), &list); 2177 } 2178 } 2179 if ((node->Kinds() & B_BUFFER_CONSUMER) != 0) { 2180 if (BBufferConsumer* consumer = dynamic_cast<BBufferConsumer*>(node)) { 2181 List<media_input> list; 2182 if (GetAllInputs(consumer, &list) == B_OK) 2183 PublishInputs(node->Node(), &list); 2184 } 2185 } 2186 2187 TRACE("BMediaRoster::RegisterNode: sending NodesCreated\n"); 2188 2189 BPrivate::media::notifications::NodesCreated(&reply.node_id, 1); 2190 2191 TRACE("BMediaRoster::RegisterNode: finished\n"); 2192 2193 /* 2194 TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld, 2195 addon %ld, flavor %ld\n", node->Name(), node->ID(), addOnID, flavorID); 2196 TRACE("BMediaRoster::RegisterNode: node this %p\n", node); 2197 TRACE("BMediaRoster::RegisterNode: node fConsumerThis %p\n", 2198 node->fConsumerThis); 2199 TRACE("BMediaRoster::RegisterNode: node fProducerThis %p\n", 2200 node->fProducerThis); 2201 TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n", 2202 node->fFileInterfaceThis); 2203 TRACE("BMediaRoster::RegisterNode: node fControllableThis %p\n", 2204 node->fControllableThis); 2205 TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis %p\n", 2206 node->fTimeSourceThis); 2207 */ 2208 return B_OK; 2209 } 2210 2211 2212 status_t 2213 BMediaRoster::UnregisterNode(BMediaNode* node) 2214 { 2215 CALLED(); 2216 if (node == NULL) 2217 return B_BAD_VALUE; 2218 2219 TRACE("BMediaRoster::UnregisterNode %ld (%p)\n", node->ID(), node); 2220 2221 if ((node->fKinds & NODE_KIND_NO_REFCOUNTING) !=0) { 2222 TRACE("BMediaRoster::UnregisterNode, trying to unregister reference " 2223 "counting disabled timesource, node %ld, port %ld, team %ld\n", 2224 node->ID(), node->ControlPort(), BPrivate::current_team()); 2225 return B_OK; 2226 } 2227 if (node->ID() == NODE_UNREGISTERED_ID) { 2228 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name " 2229 "'%s' already unregistered\n", node->ID(), node->Name()); 2230 return B_OK; 2231 } 2232 if (node->fRefCount != 0) { 2233 PRINT(1, "Warning: BMediaRoster::UnregisterNode: node id %ld, name " 2234 "'%s' has local reference count of %ld\n", node->ID(), node->Name(), 2235 node->fRefCount); 2236 // no return here, we continue and unregister! 2237 } 2238 2239 // Calling BMediaAddOn::GetConfigurationFor(BMediaNode *node, 2240 // BMessage *config) if this node was instanciated by an add-on needs to 2241 // be done *somewhere* 2242 // We can't do it here because it is already to late (destructor of the node 2243 // might have been called). 2244 2245 server_unregister_node_request request; 2246 request.node_id = node->ID(); 2247 request.team = BPrivate::current_team(); 2248 2249 // send a notification 2250 BPrivate::media::notifications::NodesDeleted(&request.node_id, 1); 2251 2252 server_unregister_node_reply reply; 2253 reply.add_on_id = -1; 2254 status_t status = QueryServer(SERVER_UNREGISTER_NODE, &request, 2255 sizeof(request), &reply, sizeof(reply)); 2256 if (status != B_OK) { 2257 ERROR("BMediaRoster::UnregisterNode: failed to unregister node id %" 2258 B_PRId32 ", name '%s': %s\n", node->ID(), node->Name(), 2259 strerror(status)); 2260 BMediaAddOn *addon = node->AddOn(&reply.flavor_id); 2261 if (addon != NULL) 2262 reply.add_on_id = addon->AddonID(); 2263 } 2264 2265 if (reply.add_on_id != -1) { 2266 // TODO: this doesn't look right 2267 // Small problem here, we can't use DormantNodeManager::PutAddOn(), as 2268 // UnregisterNode() is called by a dormant node itself (by the 2269 // destructor). 2270 // The add-on that contains the node needs to remain in memory until the 2271 // destructor execution is finished. 2272 // DormantNodeManager::PutAddOnDelayed() will delay unloading. 2273 gDormantNodeManager->PutAddOnDelayed(reply.add_on_id); 2274 2275 status = MediaRosterEx(this)->DecrementAddonFlavorInstancesCount( 2276 reply.add_on_id, reply.flavor_id); 2277 if (status != B_OK) { 2278 ERROR("BMediaRoster::UnregisterNode: " 2279 "DecrementAddonFlavorInstancesCount() failed\n"); 2280 // this is really a problem, but we can't fail now 2281 } 2282 } 2283 2284 // we are a friend class of BMediaNode and invalidate this member variable 2285 node->fNodeID = NODE_UNREGISTERED_ID; 2286 2287 return status; 2288 } 2289 2290 2291 //! Thread safe for multiple calls to Roster() 2292 /*static*/ BMediaRoster* 2293 BMediaRoster::Roster(status_t* out_error) 2294 { 2295 BAutolock lock(sInitLocker); 2296 2297 if (be_app == NULL) 2298 TRACE("Warning! You should have a valid BApplication."); 2299 2300 if (!lock.IsLocked()) 2301 return NULL; 2302 2303 if (out_error) 2304 *out_error = B_OK; 2305 2306 if (sDefaultInstance == NULL) { 2307 status_t err; 2308 sDefaultInstance = new (std::nothrow) BMediaRosterEx(&err); 2309 if (sDefaultInstance == NULL) 2310 err = B_NO_MEMORY; 2311 else if (err != B_OK) { 2312 if (sDefaultInstance) { 2313 sDefaultInstance->Lock(); 2314 sDefaultInstance->Quit(); 2315 sDefaultInstance = NULL; 2316 } 2317 if (out_error) 2318 *out_error = err; 2319 } else if (be_app != NULL) { 2320 be_app->RegisterLooper(sDefaultInstance); 2321 } 2322 } 2323 2324 return sDefaultInstance; 2325 } 2326 2327 2328 /*static*/ BMediaRoster* 2329 BMediaRoster::CurrentRoster() 2330 { 2331 return sDefaultInstance; 2332 } 2333 2334 2335 status_t 2336 BMediaRoster::SetTimeSourceFor(media_node_id node, media_node_id time_source) 2337 { 2338 CALLED(); 2339 if (IS_INVALID_NODEID(node) || IS_INVALID_NODEID(time_source)) 2340 return B_BAD_VALUE; 2341 2342 media_node clone; 2343 // We need to get a clone of the node to have a port id 2344 status_t result = GetNodeFor(node, &clone); 2345 if (result == B_OK) { 2346 // We just send the request to set time_source-id as 2347 // timesource to the node, the NODE_SET_TIMESOURCE handler 2348 // code will do the real assignment. 2349 result = B_OK; 2350 node_set_timesource_command cmd; 2351 cmd.timesource_id = time_source; 2352 result = SendToPort(clone.port, NODE_SET_TIMESOURCE, 2353 &cmd, sizeof(cmd)); 2354 if (result != B_OK) { 2355 ERROR("BMediaRoster::SetTimeSourceFor" 2356 "sending NODE_SET_TIMESOURCE failed, node id %" 2357 B_PRId32 "\n", clone.node); 2358 } 2359 // We release the clone 2360 result = ReleaseNode(clone); 2361 if (result != B_OK) { 2362 ERROR("BMediaRoster::SetTimeSourceFor, ReleaseNode failed," 2363 " node id %" B_PRId32 "\n", clone.node); 2364 } 2365 } else { 2366 ERROR("BMediaRoster::SetTimeSourceFor GetCloneForID failed, " 2367 "node id %" B_PRId32 "\n", node); 2368 } 2369 2370 if (result == B_OK) { 2371 // Notify the server 2372 server_set_node_timesource_request request; 2373 server_set_node_timesource_reply reply; 2374 2375 request.node_id = node; 2376 request.timesource_id = time_source; 2377 2378 result = QueryServer(SERVER_SET_NODE_TIMESOURCE, &request, 2379 sizeof(request), &reply, sizeof(reply)); 2380 if (result != B_OK) { 2381 ERROR("BMediaRoster::SetTimeSourceFor, sending NODE_SET_TIMESOURCE " 2382 "failed, node id %" B_PRId32 "\n", node); 2383 } else { 2384 TRACE("BMediaRoster::SetTimeSourceFor: node %" B_PRId32 " time source %" 2385 B_PRId32 " OK\n", node, time_source); 2386 } 2387 } 2388 return result; 2389 } 2390 2391 2392 status_t 2393 BMediaRoster::GetParameterWebFor(const media_node& node, BParameterWeb** _web) 2394 { 2395 CALLED(); 2396 if (_web == NULL) 2397 return B_BAD_VALUE; 2398 if (IS_INVALID_NODE(node)) 2399 return B_MEDIA_BAD_NODE; 2400 if ((node.kind & B_CONTROLLABLE) == 0) 2401 return B_MEDIA_BAD_NODE; 2402 2403 controllable_get_parameter_web_request request; 2404 controllable_get_parameter_web_reply reply; 2405 int32 requestsize[] = {B_PAGE_SIZE, 4 * B_PAGE_SIZE, 16 * B_PAGE_SIZE, 2406 64 * B_PAGE_SIZE, 128 * B_PAGE_SIZE, 256 * B_PAGE_SIZE, 0}; 2407 int32 size; 2408 2409 // TODO: it might be better to query the node for the (current) parameter 2410 // size first 2411 for (int i = 0; (size = requestsize[i]) != 0; i++) { 2412 status_t rv; 2413 area_id area; 2414 void *data; 2415 area = create_area("parameter web data", &data, B_ANY_ADDRESS, size, 2416 B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 2417 if (area < B_OK) { 2418 ERROR("BMediaRoster::GetParameterWebFor couldn't create area of " 2419 "size %" B_PRId32 "\n", size); 2420 return B_ERROR; 2421 } 2422 request.max_size = size; 2423 request.area = area; 2424 rv = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_WEB, &request, 2425 sizeof(request), &reply, sizeof(reply)); 2426 if (rv != B_OK) { 2427 ERROR("BMediaRoster::GetParameterWebFor " 2428 "CONTROLLABLE_GET_PARAMETER_WEB failed\n"); 2429 delete_area(area); 2430 return B_ERROR; 2431 } 2432 if (reply.size == 0) { 2433 // no parameter web available 2434 // TODO: should we return an error? 2435 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32 2436 " has no parameter web\n", node.node); 2437 *_web = new (std::nothrow) BParameterWeb(); 2438 delete_area(area); 2439 return *_web != NULL ? B_OK : B_NO_MEMORY; 2440 } 2441 if (reply.size > 0) { 2442 // we got a flattened parameter web! 2443 BParameterWeb* web = new (std::nothrow) BParameterWeb(); 2444 if (web == NULL) 2445 rv = B_NO_MEMORY; 2446 else { 2447 rv = web->Unflatten(reply.code, data, reply.size); 2448 if (rv != B_OK) { 2449 ERROR("BMediaRoster::GetParameterWebFor Unflatten failed, " 2450 "%s\n", strerror(rv)); 2451 delete web; 2452 } else 2453 *_web = web; 2454 } 2455 2456 delete_area(area); 2457 return rv; 2458 } 2459 delete_area(area); 2460 ASSERT(reply.size == -1); 2461 // parameter web data was too large 2462 // loop and try a larger size 2463 } 2464 ERROR("BMediaRoster::GetParameterWebFor node %" B_PRId32 " has no " 2465 "parameter web larger than %" B_PRId32 "\n", node.node, size); 2466 return B_ERROR; 2467 } 2468 2469 2470 status_t 2471 BMediaRoster::StartControlPanel(const media_node& node, BMessenger* _messenger) 2472 { 2473 CALLED(); 2474 2475 controllable_start_control_panel_request request; 2476 controllable_start_control_panel_reply reply; 2477 2478 request.node = node; 2479 2480 status_t rv; 2481 rv = QueryPort(node.port, CONTROLLABLE_START_CONTROL_PANEL, &request, 2482 sizeof(request), &reply, sizeof(reply)); 2483 if (rv != B_OK) 2484 return rv; 2485 2486 if (reply.team != -1 && _messenger != NULL) 2487 *_messenger = BMessenger(NULL, reply.team); 2488 2489 return B_OK; 2490 } 2491 2492 2493 status_t 2494 BMediaRoster::GetDormantNodes(dormant_node_info* _info, int32* _count, 2495 const media_format* hasInput, const media_format* hasOutput, 2496 const char* name, uint64 requireKinds, uint64 denyKinds) 2497 { 2498 CALLED(); 2499 if (_info == NULL || _count == NULL || *_count <= 0) 2500 return B_BAD_VALUE; 2501 2502 server_get_dormant_nodes_request request; 2503 request.max_count = *_count; 2504 request.has_input = hasInput != NULL; 2505 if (hasInput != NULL) { 2506 // TODO: we should not make a flat copy of media_format 2507 request.input_format = *hasInput; 2508 } 2509 request.has_output = hasOutput != NULL; 2510 if (hasOutput != NULL) { 2511 // TODO: we should not make a flat copy of media_format 2512 request.output_format = *hasOutput; 2513 } 2514 2515 request.has_name = name != NULL; 2516 if (name != NULL) 2517 strlcpy(request.name, name, sizeof(request.name)); 2518 2519 request.require_kinds = requireKinds; 2520 request.deny_kinds = denyKinds; 2521 2522 server_get_dormant_nodes_reply reply; 2523 status_t status = QueryServer(SERVER_GET_DORMANT_NODES, &request, 2524 sizeof(request), &reply, sizeof(reply)); 2525 if (status != B_OK) 2526 return status; 2527 2528 *_count = reply.count; 2529 2530 if (reply.count > 0) { 2531 int32 code; 2532 status = read_port(request.reply_port, &code, _info, 2533 reply.count * sizeof(dormant_node_info)); 2534 if (status < B_OK) 2535 reply.result = status; 2536 } 2537 2538 return reply.result; 2539 } 2540 2541 2542 /*! This function is used to do the real work of instantiating a dormant node. 2543 It is either called by the media_addon_server to instantiate a global node, 2544 or it gets called from BMediaRoster::InstantiateDormantNode() to create a 2545 local one. 2546 2547 Checks concerning global/local are not done here. 2548 */ 2549 status_t 2550 BMediaRosterEx::InstantiateDormantNode(media_addon_id addonID, int32 flavorID, 2551 team_id creator, media_node *_node) 2552 { 2553 // This function is always called from the correct context, if the node 2554 // is supposed to be global, it is called from the media_addon_server. 2555 2556 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that 2557 // resides in the media_addon_server 2558 2559 // RegisterNode() must be called for nodes instantiated from add-ons, 2560 // since the media kit warrants that it's done automatically. 2561 2562 // addonID Indicates the ID number of the media add-on in which the 2563 // node resides. 2564 // flavorID Indicates the internal ID number that the add-on uses to 2565 // identify the flavor, this is the number that was published 2566 // by BMediaAddOn::GetFlavorAt() in the 2567 // flavor_info::internal_id field. 2568 // creator The creator team is -1 if nodes are created locally. If 2569 // created globally, it will contain (while called in 2570 // media_addon_server context) the team-id of the team that 2571 // requested the instantiation. 2572 2573 TRACE("BMediaRosterEx::InstantiateDormantNode: addonID %" B_PRId32 2574 ", flavorID %" B_PRId32 "\n", addonID, flavorID); 2575 2576 // Get flavor_info from the server 2577 dormant_flavor_info info; 2578 status_t rv; 2579 rv = GetDormantFlavorInfo(addonID, flavorID, &info); 2580 if (rv != B_OK) { 2581 ERROR("BMediaRosterEx::InstantiateDormantNode error: failed to get " 2582 "dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %" 2583 B_PRId32 "\n", addonID, flavorID); 2584 return B_ERROR; 2585 } 2586 2587 ASSERT(info.internal_id == flavorID); 2588 2589 // load the BMediaAddOn object 2590 BMediaAddOn* addon = gDormantNodeManager->GetAddOn(addonID); 2591 if (addon == NULL) { 2592 ERROR("BMediaRosterEx::InstantiateDormantNode: GetAddon failed\n"); 2593 return B_ERROR; 2594 } 2595 2596 // Now we need to try to increment the use count of this addon flavor 2597 // in the server. This can fail if the total number instances of this 2598 // flavor is limited. 2599 rv = IncrementAddonFlavorInstancesCount(addonID, flavorID); 2600 if (rv != B_OK) { 2601 ERROR("BMediaRosterEx::InstantiateDormantNode error: can't create " 2602 "more nodes for addon-id %" B_PRId32 ", flavor-id %" B_PRId32 "\n", 2603 addonID, flavorID); 2604 // Put the addon back into the pool 2605 gDormantNodeManager->PutAddOn(addonID); 2606 return B_ERROR; 2607 } 2608 2609 BMessage config; 2610 rv = LoadNodeConfiguration(addonID, flavorID, &config); 2611 if (rv != B_OK) { 2612 ERROR("BMediaRosterEx::InstantiateDormantNode: couldn't load " 2613 "configuration for addon-id %" B_PRId32 ", flavor-id %" B_PRId32 2614 "\n", addonID, flavorID); 2615 // do not return, this is a minor problem, not a reason to fail 2616 } 2617 2618 status_t status = B_OK; 2619 BMediaNode* node = addon->InstantiateNodeFor(&info, &config, &status); 2620 if (node == NULL) { 2621 ERROR("BMediaRosterEx::InstantiateDormantNode: InstantiateNodeFor " 2622 "failed\n"); 2623 2624 // Put the addon back into the pool 2625 gDormantNodeManager->PutAddOn(addonID); 2626 2627 // We must decrement the use count of this addon flavor in the 2628 // server to compensate the increment done in the beginning. 2629 rv = DecrementAddonFlavorInstancesCount(addonID, flavorID); 2630 if (rv != B_OK) { 2631 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon" 2632 "FlavorInstancesCount failed\n"); 2633 } 2634 return status != B_OK ? status : B_ERROR; 2635 } 2636 2637 rv = RegisterNode(node, addonID, flavorID); 2638 if (rv != B_OK) { 2639 ERROR("BMediaRosterEx::InstantiateDormantNode: RegisterNode failed\n"); 2640 delete node; 2641 // Put the addon back into the pool 2642 gDormantNodeManager->PutAddOn(addonID); 2643 // We must decrement the use count of this addon flavor in the 2644 // server to compensate the increment done in the beginning. 2645 rv = DecrementAddonFlavorInstancesCount(addonID, flavorID); 2646 if (rv != B_OK) { 2647 ERROR("BMediaRosterEx::InstantiateDormantNode: DecrementAddon" 2648 "FlavorInstancesCount failed\n"); 2649 } 2650 return B_ERROR; 2651 } 2652 2653 if (creator != -1) { 2654 // send a message to the server to assign team "creator" as creator 2655 // of node "node->ID()" 2656 printf("!!! BMediaRosterEx::InstantiateDormantNode assigning team %" 2657 B_PRId32 " as creator of node %" B_PRId32 "\n", creator, 2658 node->ID()); 2659 2660 rv = MediaRosterEx(this)->SetNodeCreator(node->ID(), creator); 2661 if (rv != B_OK) { 2662 ERROR("BMediaRosterEx::InstantiateDormantNode failed to assign " 2663 "team %" B_PRId32 " as creator of node %" B_PRId32 "\n", 2664 creator, node->ID()); 2665 // do not return, this is a minor problem, not a reason to fail 2666 } 2667 } 2668 2669 // RegisterNode() does remember the add-on id in the server 2670 // and UnregisterNode() will call DormantNodeManager::PutAddon() 2671 // when the node is unregistered. 2672 2673 *_node = node->Node(); 2674 2675 TRACE("BMediaRosterEx::InstantiateDormantNode: addon-id %" B_PRId32 2676 ", flavor_id %" B_PRId32 " instanciated as node %" B_PRId32 ", port %" 2677 B_PRId32 " in team %" B_PRId32 "\n", addonID, flavorID, _node->node, 2678 _node->port, BPrivate::current_team()); 2679 2680 return B_OK; 2681 } 2682 2683 2684 status_t 2685 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info, 2686 media_node* _node, uint32 flags) 2687 { 2688 CALLED(); 2689 if (_node == NULL) 2690 return B_BAD_VALUE; 2691 if (info.addon <= B_OK) { 2692 ERROR("BMediaRoster::InstantiateDormantNode error: addon-id %" B_PRId32 2693 " invalid.\n", info.addon); 2694 return B_BAD_VALUE; 2695 } 2696 2697 printf("BMediaRoster::InstantiateDormantNode: addon-id %" B_PRId32 2698 ", flavor_id %" B_PRId32 ", flags 0x%" B_PRIx32 "\n", info.addon, 2699 info.flavor_id, flags); 2700 2701 // Get flavor_info from the server 2702 // TODO: this is a little overhead, as we get the full blown 2703 // dormant_flavor_info, 2704 // TODO: but only need the flags. 2705 dormant_flavor_info flavorInfo; 2706 status_t rv; 2707 rv = MediaRosterEx(this)->GetDormantFlavorInfo(info.addon, info.flavor_id, 2708 &flavorInfo); 2709 if (rv != B_OK) { 2710 ERROR("BMediaRoster::InstantiateDormantNode: failed to get " 2711 "dormant_flavor_info for addon-id %" B_PRId32 ", flavor-id %" 2712 B_PRId32 "\n", info.addon, info.flavor_id); 2713 return B_NAME_NOT_FOUND; 2714 } 2715 2716 ASSERT(flavorInfo.internal_id == info.flavor_id); 2717 2718 #if DEBUG 2719 printf("BMediaRoster::InstantiateDormantNode: name \"%s\", info \"%s\", " 2720 "flavor_flags 0x%" B_PRIx32 ", internal_id %" B_PRId32 2721 ", possible_count %" B_PRId32 "\n", flavorInfo.name, flavorInfo.info, 2722 flavorInfo.flavor_flags, flavorInfo.internal_id, 2723 flavorInfo.possible_count); 2724 2725 if ((flags & B_FLAVOR_IS_LOCAL) != 0) { 2726 printf("BMediaRoster::InstantiateDormantNode: caller requested " 2727 "B_FLAVOR_IS_LOCAL\n"); 2728 } 2729 if ((flags & B_FLAVOR_IS_GLOBAL) != 0) { 2730 printf("BMediaRoster::InstantiateDormantNode: caller requested " 2731 "B_FLAVOR_IS_GLOBAL\n"); 2732 } 2733 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0) { 2734 printf("BMediaRoster::InstantiateDormantNode: node requires " 2735 "B_FLAVOR_IS_LOCAL\n"); 2736 } 2737 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0) { 2738 printf("BMediaRoster::InstantiateDormantNode: node requires " 2739 "B_FLAVOR_IS_GLOBAL\n"); 2740 } 2741 #endif 2742 2743 // Make sure that flags demanded by the dormant node and those requested 2744 // by the caller are not incompatible. 2745 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0 2746 && (flags & B_FLAVOR_IS_LOCAL) != 0) { 2747 ERROR("BMediaRoster::InstantiateDormantNode: requested " 2748 "B_FLAVOR_IS_LOCAL, but dormant node has B_FLAVOR_IS_GLOBAL\n"); 2749 return B_NAME_NOT_FOUND; 2750 } 2751 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_LOCAL) != 0 2752 && (flags & B_FLAVOR_IS_GLOBAL) != 0) { 2753 ERROR("BMediaRoster::InstantiateDormantNode: requested " 2754 "B_FLAVOR_IS_GLOBAL, but dormant node has B_FLAVOR_IS_LOCAL\n"); 2755 return B_NAME_NOT_FOUND; 2756 } 2757 2758 // If either the node, or the caller requested to make the instance global 2759 // we will do it by forwarding this request into the media_addon_server, 2760 // which in turn will call BMediaRosterEx::InstantiateDormantNode to create 2761 // the node there and make it globally available. 2762 if ((flavorInfo.flavor_flags & B_FLAVOR_IS_GLOBAL) != 0 2763 || (flags & B_FLAVOR_IS_GLOBAL) != 0) { 2764 TRACE("BMediaRoster::InstantiateDormantNode: creating global object " 2765 "in media_addon_server\n"); 2766 2767 add_on_server_instantiate_dormant_node_request request; 2768 add_on_server_instantiate_dormant_node_reply reply; 2769 request.add_on_id = info.addon; 2770 request.flavor_id = info.flavor_id; 2771 request.creator_team = BPrivate::current_team(); 2772 // creator team is allowed to also release global nodes 2773 rv = QueryAddOnServer(ADD_ON_SERVER_INSTANTIATE_DORMANT_NODE, &request, 2774 sizeof(request), &reply, sizeof(reply)); 2775 if (rv == B_OK) 2776 *_node = reply.node; 2777 } else { 2778 // creator team = -1, as this is a local node 2779 rv = MediaRosterEx(this)->InstantiateDormantNode(info.addon, 2780 info.flavor_id, -1, _node); 2781 } 2782 if (rv != B_OK) { 2783 *_node = media_node::null; 2784 return B_NAME_NOT_FOUND; 2785 } 2786 return B_OK; 2787 } 2788 2789 2790 status_t 2791 BMediaRoster::InstantiateDormantNode(const dormant_node_info& info, 2792 media_node* _node) 2793 { 2794 return InstantiateDormantNode(info, _node, 0); 2795 } 2796 2797 2798 status_t 2799 BMediaRoster::GetDormantNodeFor(const media_node& node, 2800 dormant_node_info* _info) 2801 { 2802 CALLED(); 2803 if (_info == NULL) 2804 return B_BAD_VALUE; 2805 if (IS_INVALID_NODE(node)) 2806 return B_MEDIA_BAD_NODE; 2807 2808 server_get_dormant_node_for_request request; 2809 server_get_dormant_node_for_reply reply; 2810 status_t rv; 2811 2812 request.node = node; 2813 2814 rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request), 2815 &reply, sizeof(reply)); 2816 if (rv != B_OK) 2817 return rv; 2818 2819 *_info = reply.node_info; 2820 return B_OK; 2821 } 2822 2823 2824 status_t 2825 BMediaRosterEx::GetDormantFlavorInfo(media_addon_id addonID, int32 flavorID, 2826 dormant_flavor_info* _flavor) 2827 { 2828 CALLED(); 2829 if (_flavor == NULL) 2830 return B_BAD_VALUE; 2831 2832 // TODO: better use an area here as well! 2833 2834 server_get_dormant_flavor_info_reply* reply 2835 = (server_get_dormant_flavor_info_reply*)malloc(16300); 2836 if (reply == NULL) 2837 return B_NO_MEMORY; 2838 2839 server_get_dormant_flavor_info_request request; 2840 request.add_on_id = addonID; 2841 request.flavor_id = flavorID; 2842 2843 status_t status = QueryServer(SERVER_GET_DORMANT_FLAVOR_INFO, &request, 2844 sizeof(request), reply, 16300); 2845 if (status != B_OK) { 2846 free(reply); 2847 return status; 2848 } 2849 2850 if (reply->result == B_OK) { 2851 status = _flavor->Unflatten(reply->type, &reply->flattened_data, 2852 reply->flattened_size); 2853 } else 2854 status = reply->result; 2855 2856 free(reply); 2857 return status; 2858 } 2859 2860 2861 status_t 2862 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info& dormant, 2863 dormant_flavor_info* _flavor) 2864 { 2865 return MediaRosterEx(this)->GetDormantFlavorInfo(dormant.addon, 2866 dormant.flavor_id, _flavor); 2867 } 2868 2869 2870 // Reports in outLatency the maximum latency found downstream from 2871 // the specified BBufferProducer, producer, given the current connections. 2872 status_t 2873 BMediaRoster::GetLatencyFor(const media_node& producer, bigtime_t* _latency) 2874 { 2875 CALLED(); 2876 if (_latency == NULL) 2877 return B_BAD_VALUE; 2878 if (IS_INVALID_NODE(producer) 2879 || (producer.kind & B_BUFFER_PRODUCER) == 0) 2880 return B_MEDIA_BAD_NODE; 2881 2882 producer_get_latency_request request; 2883 producer_get_latency_reply reply; 2884 status_t rv; 2885 2886 rv = QueryPort(producer.port, PRODUCER_GET_LATENCY, &request, 2887 sizeof(request), &reply, sizeof(reply)); 2888 if (rv != B_OK) 2889 return rv; 2890 2891 *_latency = reply.latency; 2892 2893 // printf("BMediaRoster::GetLatencyFor producer %ld has maximum latency %Ld\n", producer.node, *out_latency); 2894 return B_OK; 2895 } 2896 2897 2898 status_t 2899 BMediaRoster::GetInitialLatencyFor(const media_node& producer, 2900 bigtime_t* _latency, uint32* _flags) 2901 { 2902 CALLED(); 2903 if (_latency == NULL) 2904 return B_BAD_VALUE; 2905 if (IS_INVALID_NODE(producer) 2906 || (producer.kind & B_BUFFER_PRODUCER) == 0) 2907 return B_MEDIA_BAD_NODE; 2908 2909 producer_get_initial_latency_request request; 2910 producer_get_initial_latency_reply reply; 2911 status_t rv; 2912 2913 rv = QueryPort(producer.port, PRODUCER_GET_INITIAL_LATENCY, &request, 2914 sizeof(request), &reply, sizeof(reply)); 2915 if (rv != B_OK) 2916 return rv; 2917 2918 *_latency = reply.initial_latency; 2919 if (_flags != NULL) 2920 *_flags = reply.flags; 2921 2922 TRACE("BMediaRoster::GetInitialLatencyFor producer %" B_PRId32 " has " 2923 "maximum initial latency %" B_PRId64 "\n", producer.node, *_latency); 2924 return B_OK; 2925 } 2926 2927 2928 status_t 2929 BMediaRoster::GetStartLatencyFor(const media_node& timeSource, 2930 bigtime_t* _latency) 2931 { 2932 CALLED(); 2933 if (_latency == NULL) 2934 return B_BAD_VALUE; 2935 if (IS_INVALID_NODE(timeSource) 2936 || (timeSource.kind & B_TIME_SOURCE) == 0) 2937 return B_MEDIA_BAD_NODE; 2938 2939 timesource_get_start_latency_request request; 2940 timesource_get_start_latency_reply reply; 2941 status_t rv; 2942 2943 rv = QueryPort(timeSource.port, TIMESOURCE_GET_START_LATENCY, &request, 2944 sizeof(request), &reply, sizeof(reply)); 2945 if (rv != B_OK) 2946 return rv; 2947 2948 *_latency = reply.start_latency; 2949 2950 TRACE("BMediaRoster::GetStartLatencyFor timesource %" B_PRId32 " has " 2951 "maximum initial latency %" B_PRId64 "\n", timeSource.node, *_latency); 2952 return B_OK; 2953 } 2954 2955 2956 status_t 2957 BMediaRoster::GetFileFormatsFor(const media_node& fileInterface, 2958 media_file_format* _formats, int32* _numFormats) 2959 { 2960 CALLED(); 2961 2962 if (IS_INVALID_NODE(fileInterface) 2963 || (fileInterface.kind & B_FILE_INTERFACE) == 0) 2964 return B_MEDIA_BAD_NODE; 2965 2966 if (_numFormats == NULL || *_numFormats < 1) 2967 return B_BAD_VALUE; 2968 2969 fileinterface_get_formats_request request; 2970 fileinterface_get_formats_reply reply; 2971 2972 media_file_format* formats; 2973 size_t needSize = sizeof(media_file_format) * *_numFormats; 2974 size_t size = (needSize + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1); 2975 2976 area_id area = create_area("formats area", (void**)&formats, 2977 B_ANY_ADDRESS, size, B_NO_LOCK, 2978 B_READ_AREA | B_WRITE_AREA); 2979 2980 if (area < 0) 2981 return B_NO_MEMORY; 2982 2983 request.num_formats = *_numFormats; 2984 request.data_area = area; 2985 2986 status_t status = QueryPort(fileInterface.port, 2987 FILEINTERFACE_GET_FORMATS, &request, 2988 sizeof(request), &reply, sizeof(reply)); 2989 2990 if (status == B_OK) { 2991 memcpy(_formats, formats, sizeof(media_file_format)*reply.filled_slots); 2992 *_numFormats = reply.filled_slots; 2993 } 2994 delete_area(area); 2995 return status; 2996 } 2997 2998 2999 status_t 3000 BMediaRoster::SetRefFor(const media_node& file_interface, const entry_ref& file, 3001 bool createAndTruncate, bigtime_t* _length) 3002 { 3003 CALLED(); 3004 3005 if (IS_INVALID_NODE(file_interface) 3006 || (file_interface.kind & B_FILE_INTERFACE) == 0) 3007 return B_MEDIA_BAD_NODE; 3008 3009 fileinterface_set_ref_request request; 3010 fileinterface_set_ref_reply reply; 3011 status_t rv; 3012 3013 request.device = file.device; 3014 request.directory = file.directory; 3015 strcpy(request.name, file.name); 3016 request.create = createAndTruncate; 3017 if (_length != NULL) 3018 request.duration = *_length; 3019 3020 rv = QueryPort(file_interface.port, FILEINTERFACE_SET_REF, &request, 3021 sizeof(request), &reply, sizeof(reply)); 3022 if (rv != B_OK) 3023 return rv; 3024 3025 if (!createAndTruncate && _length) 3026 *_length = reply.duration; 3027 3028 return B_OK; 3029 } 3030 3031 3032 status_t 3033 BMediaRoster::GetRefFor(const media_node& node, entry_ref* _file, 3034 BMimeType* mimeType) 3035 { 3036 CALLED(); 3037 3038 if (IS_INVALID_NODE(node) 3039 || (node.kind & B_FILE_INTERFACE) == 0) 3040 return B_MEDIA_BAD_NODE; 3041 3042 if (!_file) 3043 return B_BAD_VALUE; 3044 3045 fileinterface_get_ref_request request; 3046 fileinterface_get_ref_reply reply; 3047 status_t rv; 3048 3049 rv = QueryPort(node.port, FILEINTERFACE_GET_REF, &request, sizeof(request), 3050 &reply, sizeof(reply)); 3051 if (rv != B_OK) 3052 return rv; 3053 3054 *_file = entry_ref(reply.device, reply.directory, reply.name); 3055 3056 if (mimeType) 3057 mimeType->SetTo(reply.mimetype); 3058 3059 return B_OK; 3060 } 3061 3062 3063 status_t 3064 BMediaRoster::SniffRefFor(const media_node& file_interface, 3065 const entry_ref& file, BMimeType* mimeType, float* _capability) 3066 { 3067 CALLED(); 3068 3069 if (IS_INVALID_NODE(file_interface) 3070 || (file_interface.kind & B_FILE_INTERFACE) == 0) 3071 return B_MEDIA_BAD_NODE; 3072 3073 if (mimeType == NULL || _capability == NULL) 3074 return B_BAD_VALUE; 3075 3076 fileinterface_sniff_ref_request request; 3077 fileinterface_sniff_ref_reply reply; 3078 status_t rv; 3079 3080 request.device = file.device; 3081 request.directory = file.directory; 3082 strcpy(request.name, file.name); 3083 3084 rv = QueryPort(file_interface.port, FILEINTERFACE_SNIFF_REF, &request, 3085 sizeof(request), &reply, sizeof(reply)); 3086 if (rv != B_OK) 3087 return rv; 3088 3089 mimeType->SetTo(reply.mimetype); 3090 *_capability = reply.capability; 3091 3092 return B_OK; 3093 } 3094 3095 3096 /*! This is the generic "here's a file, now can someone please play it" 3097 interface. 3098 */ 3099 status_t 3100 BMediaRoster::SniffRef(const entry_ref& file, uint64 requireNodeKinds, 3101 dormant_node_info* _node, BMimeType* mimeType) 3102 { 3103 CALLED(); 3104 3105 TRACE("BMediaRoster::SniffRef looking for a node to handle %s: 0x%" B_PRIx64 3106 "\n", file.name, requireNodeKinds); 3107 3108 if (_node == NULL) 3109 return B_BAD_VALUE; 3110 3111 BMimeType aMimeType; 3112 3113 dormant_node_info nodes[30]; 3114 int32 count = 30; 3115 int32 highestCapability = -1; 3116 float capability; 3117 3118 media_node node; 3119 3120 // Get all dormant nodes using GetDormantNodes 3121 if (GetDormantNodes(nodes, &count, NULL, NULL, NULL, requireNodeKinds | B_FILE_INTERFACE, 0) == B_OK) { 3122 // Call SniffRefFor on each node that matches requireNodeKinds 3123 for (int32 i=0;i<count;i++) { 3124 if (InstantiateDormantNode(nodes[i], &node) == B_OK) { 3125 3126 if (SniffRefFor(node, file, &aMimeType, &capability) == B_OK) { 3127 // find the first node that has 100% capability 3128 TRACE("%s has a %f%% chance of playing file\n",nodes[i].name, capability * 100.0); 3129 if (capability == 1.0) { 3130 highestCapability = i; 3131 break; 3132 } 3133 } 3134 ReleaseNode(node); 3135 } 3136 } 3137 3138 if (highestCapability != -1) { 3139 *_node = nodes[highestCapability]; 3140 3141 TRACE("BMediaRoster::SniffRef: found a node %s addon-id %" B_PRId32 3142 ", flavor_id %" B_PRId32 "\n", 3143 nodes[highestCapability].name, nodes[highestCapability].addon, 3144 nodes[highestCapability].flavor_id); 3145 3146 if (mimeType != NULL) { 3147 //*mimeType = aMimeType; -- need a copy constructor 3148 } 3149 3150 return B_OK; 3151 } 3152 3153 } 3154 3155 return B_ERROR; 3156 } 3157 3158 3159 status_t 3160 BMediaRoster::GetDormantNodeForType(const BMimeType& type, 3161 uint64 requireNodeKinds, dormant_node_info* _node) 3162 { 3163 UNIMPLEMENTED(); 3164 return B_ERROR; 3165 } 3166 3167 3168 status_t 3169 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info& node, 3170 media_file_format* _readFormats, int32 readCount, int32* _readCount) 3171 { 3172 UNIMPLEMENTED(); 3173 return B_ERROR; 3174 } 3175 3176 3177 status_t 3178 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info& node, 3179 media_file_format* _write_formats, int32 writeCount, int32* _writeCount) 3180 { 3181 UNIMPLEMENTED(); 3182 return B_ERROR; 3183 } 3184 3185 3186 status_t 3187 BMediaRoster::GetFormatFor(const media_output& output, media_format* _format, 3188 uint32 flags) 3189 { 3190 CALLED(); 3191 if (_format == NULL) 3192 return B_BAD_VALUE; 3193 if ((output.node.kind & B_BUFFER_PRODUCER) == 0) 3194 return B_MEDIA_BAD_NODE; 3195 if (IS_INVALID_SOURCE(output.source)) 3196 return B_MEDIA_BAD_SOURCE; 3197 3198 producer_format_suggestion_requested_request request; 3199 producer_format_suggestion_requested_reply reply; 3200 status_t rv; 3201 3202 request.type = B_MEDIA_UNKNOWN_TYPE; 3203 request.quality = 0; // TODO: what should this be? 3204 3205 rv = QueryPort(output.source.port, PRODUCER_FORMAT_SUGGESTION_REQUESTED, 3206 &request, sizeof(request), &reply, sizeof(reply)); 3207 if (rv != B_OK) 3208 return rv; 3209 3210 *_format = reply.format; 3211 return B_OK; 3212 } 3213 3214 3215 status_t 3216 BMediaRoster::GetFormatFor(const media_input& input, media_format* _format, 3217 uint32 flags) 3218 { 3219 CALLED(); 3220 if (_format == NULL) 3221 return B_BAD_VALUE; 3222 if ((input.node.kind & B_BUFFER_CONSUMER) == 0) 3223 return B_MEDIA_BAD_NODE; 3224 if (IS_INVALID_DESTINATION(input.destination)) 3225 return B_MEDIA_BAD_DESTINATION; 3226 3227 consumer_accept_format_request request; 3228 consumer_accept_format_reply reply; 3229 status_t rv; 3230 3231 request.dest = input.destination; 3232 memset(&request.format, 0, sizeof(request.format)); // wildcard 3233 3234 rv = QueryPort(input.destination.port, CONSUMER_ACCEPT_FORMAT, &request, 3235 sizeof(request), &reply, sizeof(reply)); 3236 if (rv != B_OK) 3237 return rv; 3238 3239 *_format = reply.format; 3240 return B_OK; 3241 } 3242 3243 3244 status_t 3245 BMediaRoster::GetFormatFor(const media_node& node, media_format* _format, 3246 float quality) 3247 { 3248 UNIMPLEMENTED(); 3249 if (_format == NULL) 3250 return B_BAD_VALUE; 3251 if (IS_INVALID_NODE(node)) 3252 return B_MEDIA_BAD_NODE; 3253 if ((node.kind & (B_BUFFER_CONSUMER | B_BUFFER_PRODUCER)) == 0) 3254 return B_MEDIA_BAD_NODE; 3255 3256 return B_ERROR; 3257 } 3258 3259 3260 ssize_t 3261 BMediaRoster::GetNodeAttributesFor(const media_node& node, 3262 media_node_attribute* _array, size_t maxCount) 3263 { 3264 CALLED(); 3265 3266 if (IS_INVALID_NODE(node)) 3267 return B_MEDIA_BAD_NODE; 3268 3269 node_get_attributes_for_request request; 3270 node_get_attributes_for_reply reply; 3271 status_t status; 3272 3273 media_node_attribute* addr = NULL; 3274 size_t totalSize = maxCount*sizeof(media_node_attribute); 3275 size_t size = (totalSize + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1); 3276 3277 area_id dataArea = create_area("attributes area", (void**)&addr, 3278 B_ANY_ADDRESS, size, B_NO_LOCK, 3279 B_READ_AREA | B_WRITE_AREA); 3280 // No need to memset the padding 3281 memset(addr, 0, totalSize); 3282 3283 if (dataArea < 0) 3284 return B_NO_MEMORY; 3285 3286 request.count = maxCount; 3287 request.area = dataArea; 3288 3289 status = QueryPort(node.port, NODE_GET_ATTRIBUTES_FOR, &request, 3290 sizeof(request), &reply, sizeof(reply)); 3291 if (status != B_OK) 3292 return status; 3293 3294 memcpy(_array, addr, reply.filled_count 3295 * sizeof(media_node_attribute)); 3296 3297 delete_area(dataArea); 3298 return reply.filled_count; 3299 } 3300 3301 3302 media_node_id 3303 BMediaRoster::NodeIDFor(port_id port) 3304 { 3305 CALLED(); 3306 3307 server_node_id_for_request request; 3308 server_node_id_for_reply reply; 3309 status_t rv; 3310 3311 request.port = port; 3312 3313 rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply, 3314 sizeof(reply)); 3315 if (rv != B_OK) { 3316 ERROR("BMediaRoster::NodeIDFor: failed (error %#" B_PRIx32 ")\n", rv); 3317 return -1; 3318 } 3319 3320 return reply.node_id; 3321 } 3322 3323 3324 status_t 3325 BMediaRoster::GetInstancesFor(media_addon_id addon, int32 flavor, 3326 media_node_id* _id, int32* _count) 3327 { 3328 CALLED(); 3329 if (_id == NULL) 3330 return B_BAD_VALUE; 3331 if (_count && *_count <= 0) 3332 return B_BAD_VALUE; 3333 3334 server_get_instances_for_request request; 3335 server_get_instances_for_reply reply; 3336 status_t rv; 3337 3338 request.max_count = (_count ? *_count : 1); 3339 request.add_on_id = addon; 3340 request.flavor_id = flavor; 3341 3342 rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request), 3343 &reply, sizeof(reply)); 3344 if (rv != B_OK) { 3345 ERROR("BMediaRoster::GetLiveNodes failed\n"); 3346 return rv; 3347 } 3348 3349 if (_count) 3350 *_count = reply.count; 3351 if (reply.count > 0) 3352 memcpy(_id, reply.node_id, sizeof(media_node_id) * reply.count); 3353 3354 return B_OK; 3355 } 3356 3357 3358 bool 3359 BMediaRoster::IsRunning() 3360 { 3361 return be_roster->IsRunning(B_MEDIA_SERVER_SIGNATURE) 3362 && be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE); 3363 } 3364 3365 3366 status_t 3367 BMediaRoster::SyncToServices(bigtime_t timeout) 3368 { 3369 BMessenger messenger(this); 3370 BMessage msg(MEDIA_ROSTER_REGISTER_SYNC); 3371 BMessage reply; 3372 3373 if (!messenger.IsValid()) 3374 return B_MEDIA_SYSTEM_FAILURE; 3375 3376 status_t ret = messenger.SendMessage(&msg, &reply, timeout, timeout); 3377 if (ret == B_TIMED_OUT || reply.what == B_NO_REPLY) 3378 return B_TIMED_OUT; 3379 else if (ret != B_OK) 3380 return ret; 3381 3382 return B_OK; 3383 } 3384 3385 3386 ssize_t 3387 BMediaRoster::AudioBufferSizeFor(int32 channelCount, uint32 sampleFormat, 3388 float frameRate, bus_type busKind) 3389 { 3390 bigtime_t bufferDuration; 3391 ssize_t bufferSize; 3392 3393 if (busKind == B_ISA_BUS || busKind == B_PCMCIA_BUS) 3394 bufferDuration = 25000; 3395 else 3396 bufferDuration = 10000; 3397 3398 bufferSize = (sampleFormat & 0xf) * channelCount 3399 * (ssize_t)((frameRate * bufferDuration) / 1000000.0); 3400 3401 printf("Suggested buffer duration %" B_PRId64 ", size %" B_PRIdSSIZE "\n", 3402 bufferDuration, bufferSize); 3403 3404 return bufferSize; 3405 } 3406 3407 3408 /*! Use MediaFlags to inquire about specific features of the Media Kit. 3409 Returns < 0 for "not present", positive size for output data size. 3410 0 means that the capability is present, but no data about it. 3411 */ 3412 /*static*/ ssize_t 3413 BMediaRoster::MediaFlags(media_flags cap, void* buffer, size_t maxSize) 3414 { 3415 UNIMPLEMENTED(); 3416 return 0; 3417 } 3418 3419 3420 // #pragma mark - BLooper overrides 3421 3422 3423 void 3424 BMediaRoster::MessageReceived(BMessage* message) 3425 { 3426 switch (message->what) { 3427 case MEDIA_ROSTER_REQUEST_NOTIFICATIONS: 3428 { 3429 RosterNotification notification; 3430 if (message->FindInt32(NOTIFICATION_PARAM_WHAT, ¬ification.what) 3431 != B_OK) { 3432 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't" 3433 "find what parameter"); 3434 return; 3435 } 3436 if (message->FindMessenger(NOTIFICATION_PARAM_MESSENGER, 3437 ¬ification.messenger) != B_OK) { 3438 TRACE("BMediaRoster MEDIA_ROSTER_REQUEST_NOTIFICATIONS can't" 3439 "find messenger"); 3440 return; 3441 } 3442 sNotificationList.Insert(notification); 3443 return; 3444 } 3445 3446 case MEDIA_ROSTER_CANCEL_NOTIFICATIONS: 3447 { 3448 RosterNotification notification; 3449 if (message->FindInt32(NOTIFICATION_PARAM_WHAT, ¬ification.what) 3450 != B_OK) { 3451 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't" 3452 "find what parameter"); 3453 return; 3454 } 3455 if (message->FindMessenger(NOTIFICATION_PARAM_MESSENGER, 3456 ¬ification.messenger) != B_OK) { 3457 TRACE("BMediaRoster MEDIA_ROSTER_CANCEL_NOTIFICATIONS can't" 3458 "find messenger"); 3459 return; 3460 } 3461 for (int32 i = 0; i < sNotificationList.CountItems(); i++) { 3462 RosterNotification* current; 3463 if (sNotificationList.Get(i, ¤t) != true) 3464 return; 3465 if (current->what == notification.what 3466 && current->messenger == notification.messenger) { 3467 sNotificationList.Remove(i); 3468 return; 3469 } 3470 } 3471 return; 3472 } 3473 3474 case MEDIA_ROSTER_REGISTER_SYNC: 3475 { 3476 BMessage reply; 3477 if (sServerIsUp) 3478 message->SendReply(&reply); 3479 else { 3480 DetachCurrentMessage(); 3481 SyncedMessage msg; 3482 msg.message = message; 3483 sSyncedMessages.Insert(msg); 3484 } 3485 return; 3486 } 3487 3488 case B_SOME_APP_LAUNCHED: 3489 { 3490 BString mimeSig; 3491 if (message->FindString("be:signature", &mimeSig) != B_OK) 3492 return; 3493 if (mimeSig != B_MEDIA_ADDON_SERVER_SIGNATURE 3494 && mimeSig != B_MEDIA_SERVER_SIGNATURE) 3495 return; 3496 3497 TRACE("BMediaRoster::MessageReceived media services are going up."); 3498 3499 if (BMediaRoster::IsRunning()) { 3500 // Wait for media services to wake up and restore our friendship 3501 if (MediaRosterEx(this)->BuildConnections() != B_OK) { 3502 TRACE("BMediaRoster::MessageReceived can't reconnect" 3503 "to media_server."); 3504 } 3505 } 3506 return; 3507 } 3508 3509 case B_SOME_APP_QUIT: 3510 { 3511 BString mimeSig; 3512 if (message->FindString("be:signature", &mimeSig) != B_OK) 3513 return; 3514 if (mimeSig != B_MEDIA_ADDON_SERVER_SIGNATURE 3515 && mimeSig != B_MEDIA_SERVER_SIGNATURE) 3516 return; 3517 3518 TRACE("BMediaRoster::MessageReceived media services are down."); 3519 3520 // Send the notification to our subscribers 3521 if (!BMediaRoster::IsRunning() && sServerIsUp == true) { 3522 sServerIsUp = false; 3523 for (int32 i = 0; i < sNotificationList.CountItems(); i++) { 3524 RosterNotification* current; 3525 if (sNotificationList.Get(i, ¤t) != true) 3526 return; 3527 if (current->what == B_MEDIA_SERVER_QUIT) { 3528 if (current->messenger.SendMessage( 3529 B_MEDIA_SERVER_QUIT) != B_OK) { 3530 if(!current->messenger.IsValid()) 3531 sNotificationList.Remove(i); 3532 } 3533 } 3534 } 3535 } 3536 return; 3537 } 3538 3539 case MEDIA_SERVER_ALIVE: 3540 { 3541 if (!BMediaRoster::IsRunning()) 3542 return; 3543 3544 sServerIsUp = true; 3545 3546 TRACE("BMediaRoster::MessageReceived media services are" 3547 " finally up."); 3548 3549 if (MediaRosterEx(this)->fLaunchNotification) { 3550 progress_startup(100, NULL, NULL); 3551 if (MediaRosterEx(this)->fAutoExit) 3552 MediaRosterEx(this)->fLaunchNotification = false; 3553 } 3554 3555 BMessage reply; 3556 for (int32 i = 0; i < sSyncedMessages.CountItems(); i++) { 3557 SyncedMessage* msg; 3558 if (sSyncedMessages.Get(i, &msg) == true) { 3559 msg->message->SendReply(&reply); 3560 delete msg->message; 3561 } 3562 sSyncedMessages.Remove(i); 3563 } 3564 3565 // Send the notification to our subscribers 3566 for (int32 i = 0; i < sNotificationList.CountItems(); i++) { 3567 RosterNotification* current; 3568 if (sNotificationList.Get(i, ¤t) != true) 3569 return; 3570 if (current->what == B_MEDIA_SERVER_STARTED) { 3571 if (current->messenger.SendMessage( 3572 B_MEDIA_SERVER_STARTED) != B_OK) { 3573 if(!current->messenger.IsValid()) 3574 sNotificationList.Remove(i); 3575 } 3576 } 3577 } 3578 return; 3579 } 3580 3581 case NODE_FINAL_RELEASE: 3582 { 3583 // This function is called by a BMediaNode to delete 3584 // itself, as this needs to be done from another thread 3585 // context, it is done here. 3586 3587 BMediaNode* node = NULL; 3588 status_t err = message->FindPointer("node", 3589 reinterpret_cast<void **>(&node)); 3590 if (err == B_OK && node != NULL) 3591 node->Release(); 3592 else { 3593 TRACE("BMediaRoster::MessageReceived: CRITICAL! received" 3594 "a release request but the node can't be found."); 3595 } 3596 return; 3597 } 3598 3599 default: 3600 BLooper::MessageReceived(message); 3601 break; 3602 } 3603 } 3604 3605 3606 bool 3607 BMediaRoster::QuitRequested() 3608 { 3609 CALLED(); 3610 return true; 3611 } 3612 3613 3614 BHandler* 3615 BMediaRoster::ResolveSpecifier(BMessage* msg, int32 index, BMessage* specifier, 3616 int32 form, const char* property) 3617 { 3618 return BLooper::ResolveSpecifier(msg, index, specifier, form, property); 3619 } 3620 3621 3622 status_t 3623 BMediaRoster::GetSupportedSuites(BMessage* data) 3624 { 3625 return BLooper::GetSupportedSuites(data); 3626 } 3627 3628 3629 BMediaRoster::~BMediaRoster() 3630 { 3631 CALLED(); 3632 3633 // Unset the global instance pointer, the destructor is also called 3634 // if a client app calls Lock(); and Quit(); directly. 3635 sDefaultInstance = NULL; 3636 } 3637 3638 // #pragma mark - private BMediaRoster 3639 3640 // FBC reserved virtuals 3641 status_t BMediaRoster::_Reserved_MediaRoster_0(void*) { return B_ERROR; } 3642 status_t BMediaRoster::_Reserved_MediaRoster_1(void*) { return B_ERROR; } 3643 status_t BMediaRoster::_Reserved_MediaRoster_2(void*) { return B_ERROR; } 3644 status_t BMediaRoster::_Reserved_MediaRoster_3(void*) { return B_ERROR; } 3645 status_t BMediaRoster::_Reserved_MediaRoster_4(void*) { return B_ERROR; } 3646 status_t BMediaRoster::_Reserved_MediaRoster_5(void*) { return B_ERROR; } 3647 status_t BMediaRoster::_Reserved_MediaRoster_6(void*) { return B_ERROR; } 3648 status_t BMediaRoster::_Reserved_MediaRoster_7(void*) { return B_ERROR; } 3649 3650 3651 BMediaRoster::BMediaRoster() 3652 : 3653 BLooper("_BMediaRoster_", B_URGENT_DISPLAY_PRIORITY, 3654 B_LOOPER_PORT_DEFAULT_CAPACITY) 3655 { 3656 CALLED(); 3657 3658 // start the looper 3659 Run(); 3660 } 3661 3662 // #pragma mark - static variables 3663 3664 BMediaRoster* BMediaRoster::sDefaultInstance = NULL; 3665