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