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