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