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