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