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