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