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