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