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