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