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