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