1 /*********************************************************************** 2 * AUTHOR: Marcus Overhagen 3 * FILE: MediaRoster.cpp 4 * DESCR: 5 ***********************************************************************/ 6 #include <MediaRoster.h> 7 #include <Locker.h> 8 #include <Message.h> 9 #include <Messenger.h> 10 #include <StopWatch.h> 11 #include <OS.h> 12 #include <String.h> 13 #include <TimeSource.h> 14 #undef DEBUG 15 #define DEBUG 3 16 #include <Debug.h> 17 #include "debug.h" 18 #include "TStack.h" 19 #include "PortPool.h" 20 #include "ServerInterface.h" 21 #include "DataExchange.h" 22 #include "DormantNodeManager.h" 23 #include "Notifications.h" 24 25 namespace BPrivate { namespace media { 26 extern team_id team; 27 } } // BPrivate::media 28 29 using namespace BPrivate::media; 30 31 // the BMediaRoster destructor is private, 32 // but _DefaultDeleter is a friend class of 33 // the BMediaRoster an thus can delete it 34 class _DefaultDeleter 35 { 36 public: 37 ~_DefaultDeleter() { delete BMediaRoster::_sDefault; } 38 }; 39 40 _DefaultDeleter _deleter; 41 42 namespace BPrivate { namespace media { namespace mediaroster { 43 44 status_t GetNode(node_type type, media_node * out_node, int32 * out_input_id = NULL, BString * out_input_name = NULL); 45 status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info = NULL, const media_input *input = NULL); 46 status_t GetAllOutputs(const media_node & node, Stack<media_output> *stack); 47 status_t GetAllInputs(const media_node & node, Stack<media_input> *stack); 48 status_t PublishOutputs(const media_node & node, Stack<media_output> *stack); 49 status_t PublishInputs(const media_node & node, Stack<media_input> *stack); 50 51 status_t 52 GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name) 53 { 54 if (out_node == NULL) 55 return B_BAD_VALUE; 56 57 server_get_node_request request; 58 server_get_node_reply reply; 59 status_t rv; 60 61 request.type = type; 62 request.team = team; 63 rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply, sizeof(reply)); 64 if (rv != B_OK) 65 return rv; 66 67 *out_node = reply.node; 68 if (out_input_id) 69 *out_input_id = reply.input_id; 70 if (out_input_name) 71 *out_input_name = reply.input_name; 72 return rv; 73 } 74 75 status_t 76 SetNode(node_type type, const media_node *node, const dormant_node_info *info, const media_input *input) 77 { 78 server_set_node_request request; 79 server_set_node_reply reply; 80 81 request.type = type; 82 request.use_node = node ? true : false; 83 if (node) 84 request.node = *node; 85 request.use_dni = info ? true : false; 86 if (info) 87 request.dni = *info; 88 request.use_input = input ? true : false; 89 if (input) 90 request.input = *input; 91 92 return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply, sizeof(reply)); 93 } 94 95 status_t 96 GetAllOutputs(const media_node & node, Stack<media_output> *stack) 97 { 98 int32 cookie; 99 status_t rv; 100 status_t result; 101 102 result = B_OK; 103 cookie = 0; 104 for (;;) { 105 producer_get_next_output_request request; 106 producer_get_next_output_reply reply; 107 request.cookie = cookie; 108 rv = QueryPort(node.port, PRODUCER_GET_NEXT_OUTPUT, &request, sizeof(request), &reply, sizeof(reply)); 109 if (rv != B_OK) 110 break; 111 cookie = reply.cookie; 112 if (!stack->Push(reply.output)) { 113 TRACE("GetAllOutputs: stack->Push failed\n"); 114 result = B_ERROR; 115 } 116 } 117 118 producer_dispose_output_cookie_request request; 119 producer_dispose_output_cookie_reply reply; 120 QueryPort(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &request, sizeof(request), &reply, sizeof(reply)); 121 122 return result; 123 } 124 125 status_t 126 GetAllInputs(const media_node & node, Stack<media_input> *stack) 127 { 128 int32 cookie; 129 status_t rv; 130 status_t result; 131 132 result = B_OK; 133 cookie = 0; 134 for (;;) { 135 consumer_get_next_input_request request; 136 consumer_get_next_input_reply reply; 137 request.cookie = cookie; 138 rv = QueryPort(node.port, CONSUMER_GET_NEXT_INPUT, &request, sizeof(request), &reply, sizeof(reply)); 139 if (rv != B_OK) 140 break; 141 cookie = reply.cookie; 142 if (!stack->Push(reply.input)) { 143 TRACE("GetAllInputs: stack->Push failed\n"); 144 result = B_ERROR; 145 } 146 } 147 148 consumer_dispose_input_cookie_request request; 149 consumer_dispose_input_cookie_reply reply; 150 QueryPort(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &request, sizeof(request), &reply, sizeof(reply)); 151 152 return result; 153 } 154 155 status_t 156 PublishOutputs(const media_node & node, Stack<media_output> *stack) 157 { 158 server_publish_outputs_request request; 159 server_publish_outputs_reply reply; 160 media_output *output; 161 media_output *outputs; 162 int32 count; 163 status_t rv; 164 165 count = stack->CountItems(); 166 TRACE("PublishOutputs: publishing %ld\n", count); 167 168 request.node = node; 169 request.count = count; 170 if (count > MAX_OUTPUTS) { 171 void *start_addr; 172 size_t size; 173 size = ((count * sizeof(media_output)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 174 request.area = create_area("publish outputs", &start_addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 175 if (request.area < B_OK) { 176 TRACE("PublishOutputs: failed to create area, %#lx\n", request.area); 177 return (status_t)request.area; 178 } 179 outputs = static_cast<media_output *>(start_addr); 180 } else { 181 request.area = -1; 182 outputs = request.outputs; 183 } 184 TRACE("PublishOutputs: area %#lx\n", request.area); 185 186 for (int32 i = 0; i != count; i++) { 187 stack->GetPointerAt(i, &output); 188 outputs[i] = *output; 189 } 190 191 rv = QueryServer(SERVER_PUBLISH_OUTPUTS, &request, sizeof(request), &reply, sizeof(reply)); 192 193 if (request.area != -1) 194 delete_area(request.area); 195 196 return rv; 197 } 198 199 status_t 200 PublishInputs(const media_node & node, Stack<media_input> *stack) 201 { 202 server_publish_inputs_request request; 203 server_publish_inputs_reply reply; 204 media_input *input; 205 media_input *inputs; 206 int32 count; 207 status_t rv; 208 209 count = stack->CountItems(); 210 TRACE("PublishInputs: publishing %ld\n", count); 211 212 request.node = node; 213 request.count = count; 214 if (count > MAX_INPUTS) { 215 void *start_addr; 216 size_t size; 217 size = ((count * sizeof(media_input)) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 218 request.area = create_area("publish inputs", &start_addr, B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 219 if (request.area < B_OK) { 220 TRACE("PublishInputs: failed to create area, %#lx\n", request.area); 221 return (status_t)request.area; 222 } 223 inputs = static_cast<media_input *>(start_addr); 224 } else { 225 request.area = -1; 226 inputs = request.inputs; 227 } 228 TRACE("PublishInputs: area %#lx\n", request.area); 229 230 for (int32 i = 0; i != count; i++) { 231 stack->GetPointerAt(i, &input); 232 inputs[i] = *input; 233 } 234 235 rv = QueryServer(SERVER_PUBLISH_INPUTS, &request, sizeof(request), &reply, sizeof(reply)); 236 237 if (request.area != -1) 238 delete_area(request.area); 239 240 return rv; 241 } 242 243 } } } // namespace BPrivate::media::mediaroster 244 245 using namespace BPrivate::media::mediaroster; 246 247 /************************************************************* 248 * public BMediaRoster 249 *************************************************************/ 250 251 status_t 252 BMediaRoster::GetVideoInput(media_node * out_node) 253 { 254 CALLED(); 255 return GetNode(VIDEO_INPUT, out_node); 256 } 257 258 259 status_t 260 BMediaRoster::GetAudioInput(media_node * out_node) 261 { 262 CALLED(); 263 return GetNode(AUDIO_INPUT, out_node); 264 } 265 266 267 status_t 268 BMediaRoster::GetVideoOutput(media_node * out_node) 269 { 270 CALLED(); 271 return GetNode(VIDEO_OUTPUT, out_node); 272 } 273 274 275 status_t 276 BMediaRoster::GetAudioMixer(media_node * out_node) 277 { 278 CALLED(); 279 return GetNode(AUDIO_MIXER, out_node); 280 } 281 282 283 status_t 284 BMediaRoster::GetAudioOutput(media_node * out_node) 285 { 286 CALLED(); 287 return GetNode(AUDIO_OUTPUT, out_node); 288 } 289 290 291 status_t 292 BMediaRoster::GetAudioOutput(media_node * out_node, 293 int32 * out_input_id, 294 BString * out_input_name) 295 { 296 CALLED(); 297 return GetNode(AUDIO_OUTPUT_EX, out_node, out_input_id, out_input_name); 298 } 299 300 301 status_t 302 BMediaRoster::GetTimeSource(media_node * out_node) 303 { 304 CALLED(); 305 return GetNode(TIME_SOURCE, out_node); 306 } 307 308 309 status_t 310 BMediaRoster::SetVideoInput(const media_node & producer) 311 { 312 CALLED(); 313 return SetNode(VIDEO_INPUT, &producer); 314 } 315 316 317 status_t 318 BMediaRoster::SetVideoInput(const dormant_node_info & producer) 319 { 320 CALLED(); 321 return SetNode(VIDEO_INPUT, NULL, &producer); 322 } 323 324 325 status_t 326 BMediaRoster::SetAudioInput(const media_node & producer) 327 { 328 CALLED(); 329 return SetNode(AUDIO_INPUT, &producer); 330 } 331 332 333 status_t 334 BMediaRoster::SetAudioInput(const dormant_node_info & producer) 335 { 336 CALLED(); 337 return SetNode(AUDIO_INPUT, NULL, &producer); 338 } 339 340 341 status_t 342 BMediaRoster::SetVideoOutput(const media_node & consumer) 343 { 344 CALLED(); 345 return SetNode(VIDEO_OUTPUT, &consumer); 346 } 347 348 349 status_t 350 BMediaRoster::SetVideoOutput(const dormant_node_info & consumer) 351 { 352 CALLED(); 353 return SetNode(VIDEO_OUTPUT, NULL, &consumer); 354 } 355 356 357 status_t 358 BMediaRoster::SetAudioOutput(const media_node & consumer) 359 { 360 CALLED(); 361 return SetNode(AUDIO_OUTPUT, &consumer); 362 } 363 364 365 status_t 366 BMediaRoster::SetAudioOutput(const media_input & input_to_output) 367 { 368 CALLED(); 369 return SetNode(AUDIO_OUTPUT, NULL, NULL, &input_to_output); 370 } 371 372 373 status_t 374 BMediaRoster::SetAudioOutput(const dormant_node_info & consumer) 375 { 376 CALLED(); 377 return SetNode(AUDIO_OUTPUT, NULL, &consumer); 378 } 379 380 381 status_t 382 BMediaRoster::GetNodeFor(media_node_id node, 383 media_node * clone) 384 { 385 CALLED(); 386 if (clone == NULL) 387 return B_BAD_VALUE; 388 if (node <= 0) 389 return B_MEDIA_BAD_NODE; 390 391 server_get_node_for_request request; 392 server_get_node_for_reply reply; 393 status_t rv; 394 395 request.nodeid = node; 396 request.team = team; 397 398 rv = QueryServer(SERVER_GET_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply)); 399 if (rv != B_OK) 400 return rv; 401 402 *clone = reply.clone; 403 return B_OK; 404 } 405 406 407 status_t 408 BMediaRoster::GetSystemTimeSource(media_node * clone) 409 { 410 CALLED(); 411 return GetNode(SYSTEM_TIME_SOURCE, clone); 412 } 413 414 415 status_t 416 BMediaRoster::ReleaseNode(const media_node & node) 417 { 418 CALLED(); 419 if (node.node <= 0) 420 return B_MEDIA_BAD_NODE; 421 422 server_release_node_request request; 423 server_release_node_reply reply; 424 425 request.node = node; 426 request.team = team; 427 428 return QueryServer(SERVER_RELEASE_NODE, &request, sizeof(request), &reply, sizeof(reply)); 429 } 430 431 432 BTimeSource * 433 BMediaRoster::MakeTimeSourceFor(const media_node & for_node) 434 { 435 UNIMPLEMENTED(); 436 return 0; 437 } 438 439 440 status_t 441 BMediaRoster::Connect(const media_source & from, 442 const media_destination & to, 443 media_format * io_format, 444 media_output * out_output, 445 media_input * out_input) 446 { 447 return BMediaRoster::Connect(from, to, io_format, out_output, out_input, 0); 448 } 449 450 451 status_t 452 BMediaRoster::Connect(const media_source & from, 453 const media_destination & to, 454 media_format * io_format, 455 media_output * out_output, 456 media_input * out_input, 457 uint32 in_flags, 458 void * _reserved) 459 { 460 CALLED(); 461 if (io_format == NULL || out_output == NULL || out_input == NULL) 462 return B_BAD_VALUE; 463 if (from == media_source::null) { 464 TRACE("BMediaRoster::Connect: media_source invalid\n"); 465 return B_MEDIA_BAD_SOURCE; 466 } 467 if (to == media_destination::null) { 468 TRACE("BMediaRoster::Connect: media_destination invalid\n"); 469 return B_MEDIA_BAD_DESTINATION; 470 } 471 472 status_t rv; 473 producer_format_proposal_request request1; 474 producer_format_proposal_reply reply1; 475 476 // BBufferProducer::FormatProposal 477 request1.output = from; 478 request1.format = *io_format; 479 rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1, sizeof(request1), &reply1, sizeof(reply1)); 480 if (rv != B_OK) { 481 TRACE("BMediaRoster::Connect: aborted after BBufferProducer::FormatProposal, status = %#lx\n",rv); 482 return rv; 483 } 484 // reply1.format now contains the format proposed by the producer 485 486 consumer_accept_format_request request2; 487 consumer_accept_format_reply reply2; 488 489 // BBufferConsumer::AcceptFormat 490 request2.dest = to; 491 request2.format = reply1.format; 492 rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2, sizeof(request2), &reply2, sizeof(reply2)); 493 if (rv != B_OK) { 494 TRACE("BMediaRoster::Connect: aborted after BBufferConsumer::AcceptFormat, status = %#lx\n",rv); 495 return rv; 496 } 497 // reply2.format now contains the format accepted by the consumer 498 499 // BBufferProducer::PrepareToConnect 500 producer_prepare_to_connect_request request3; 501 producer_prepare_to_connect_reply reply3; 502 503 request3.source = from; 504 request3.destination = to; 505 request3.format = reply2.format; 506 strcpy(request3.name, "XXX some default name"); // XXX fix this 507 rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3, sizeof(request3), &reply3, sizeof(reply3)); 508 if (rv != B_OK) { 509 TRACE("BMediaRoster::Connect: aborted after BBufferProducer::PrepareToConnect, status = %#lx\n",rv); 510 return rv; 511 } 512 // reply3.format is still our pretty media format 513 // reply3.out_source the real source to be used for the connection 514 // reply3.name the name BBufferConsumer::Connected will see in the outInput->name argument 515 516 // BBufferConsumer::Connected 517 consumer_connected_request request4; 518 consumer_connected_reply reply4; 519 status_t con_status; 520 521 request4.producer = reply3.out_source; 522 request4.where = to; 523 request4.with_format = reply3.format; 524 con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4, sizeof(request4), &reply4, sizeof(reply4)); 525 if (con_status != B_OK) { 526 TRACE("BMediaRoster::Connect: aborting after BBufferConsumer::Connected, status = %#lx\n",con_status); 527 // we do NOT return here! 528 } 529 // con_status contains the status code to be supplied to BBufferProducer::Connect's status argument 530 // reply4.input contains the media_input that describes the connection from the consumer point of view 531 532 // BBufferProducer::Connect 533 producer_connect_request request5; 534 producer_connect_reply reply5; 535 536 request5.error = con_status; 537 request5.source = reply3.out_source; 538 request5.destination = reply4.input.destination; 539 request5.format = reply3.format; // XXX reply4.input.format ??? 540 strcpy(request5.name, reply4.input.name); 541 rv = QueryPort(reply4.input.source.port, PRODUCER_CONNECT, &request5, sizeof(request5), &reply5, sizeof(reply5)); 542 if (con_status != B_OK) { 543 TRACE("BMediaRoster::Connect: aborted\n"); 544 return con_status; 545 } 546 if (rv != B_OK) { 547 TRACE("BMediaRoster::Connect: aborted after BBufferProducer::Connect, status = %#lx\n",rv); 548 return rv; 549 } 550 // reply5.name contains the name assigned to the connection by the producer 551 552 // find the output node 553 // XXX isn't there a easier way? 554 media_node sourcenode; 555 GetNodeFor(NodeIDFor(from.port), &sourcenode); 556 ReleaseNode(sourcenode); 557 558 // initilize connection info 559 *io_format = reply3.format; 560 *out_input = reply4.input; 561 out_output->node = sourcenode; 562 out_output->source = reply4.input.source; 563 out_output->destination = reply4.input.destination; 564 out_output->format = reply4.input.format; 565 strcpy(out_output->name, reply5.name); 566 567 // the connection is now made 568 569 570 // XXX register connection with server 571 // XXX we should just send a notification, instead of republishing all endpoints 572 Stack<media_output> outstack; 573 Stack<media_input> instack; 574 if (B_OK == GetAllOutputs(out_output->node , &outstack)) 575 PublishOutputs(out_output->node , &outstack); 576 if (B_OK == GetAllInputs(out_input->node , &instack)) 577 PublishInputs(out_input->node, &instack); 578 579 580 // XXX if (mute) BBufferProducer::EnableOutput(false) 581 if (in_flags & B_CONNECT_MUTED) { 582 } 583 584 585 // send a notification 586 BPrivate::media::notifications::ConnectionMade(*out_input, *out_output, *io_format); 587 588 return B_OK; 589 }; 590 591 592 status_t 593 BMediaRoster::Disconnect(media_node_id source_nodeid, 594 const media_source & source, 595 media_node_id destination_nodeid, 596 const media_destination & destination) 597 { 598 CALLED(); 599 if (source_nodeid <= 0) { 600 TRACE("BMediaRoster::Disconnect: source media_node_id invalid\n"); 601 return B_MEDIA_BAD_SOURCE; 602 } 603 if (destination_nodeid <= 0) { 604 TRACE("BMediaRoster::Disconnect: source media_node_id invalid\n"); 605 return B_MEDIA_BAD_DESTINATION; 606 } 607 if (source == media_source::null) { 608 TRACE("BMediaRoster::Disconnect: media_source invalid\n"); 609 return B_MEDIA_BAD_SOURCE; 610 } 611 if (destination == media_destination::null) { 612 TRACE("BMediaRoster::Disconnect: media_destination invalid\n"); 613 return B_MEDIA_BAD_DESTINATION; 614 } 615 616 producer_disconnect_request request2; 617 producer_disconnect_reply reply2; 618 consumer_disconnected_request request1; 619 consumer_disconnected_reply reply1; 620 status_t rv1, rv2; 621 622 // XXX we should ask the server if this connection really exists 623 624 request1.source = source; 625 request1.destination = destination; 626 request2.source = source; 627 request2.destination = destination; 628 629 rv1 = QueryPort(source.port, PRODUCER_DISCONNECT, &request1, sizeof(request1), &reply1, sizeof(reply1)); 630 rv2 = QueryPort(destination.port, CONSUMER_DISCONNECTED, &request2, sizeof(request2), &reply2, sizeof(reply2)); 631 632 // XXX unregister connection with server 633 // XXX we should just send a notification, instead of republishing all endpoints 634 Stack<media_output> outstack; 635 Stack<media_input> instack; 636 media_node sourcenode; 637 media_node destnode; 638 if (B_OK == GetNodeFor(source_nodeid, &sourcenode)) { 639 if (B_OK == GetAllOutputs(sourcenode , &outstack)) 640 PublishOutputs(sourcenode , &outstack); 641 ReleaseNode(sourcenode); 642 } else TRACE("BMediaRoster::Disconnect: source GetNodeFor failed\n"); 643 if (B_OK == GetNodeFor(destination_nodeid, &destnode)) { 644 if (B_OK == GetAllInputs(destnode , &instack)) 645 PublishInputs(destnode, &instack); 646 ReleaseNode(destnode); 647 } else TRACE("BMediaRoster::Disconnect: dest GetNodeFor failed\n"); 648 649 650 // send a notification 651 BPrivate::media::notifications::ConnectionBroken(source, destination); 652 653 return (rv1 != B_OK || rv2 != B_OK) ? B_ERROR : B_OK; 654 } 655 656 657 status_t 658 BMediaRoster::StartNode(const media_node & node, 659 bigtime_t at_performance_time) 660 { 661 CALLED(); 662 if (node.node <= 0) 663 return B_MEDIA_BAD_NODE; 664 665 xfer_node_start msg; 666 msg.performance_time = at_performance_time; 667 668 return write_port(node.port, NODE_START, &msg, sizeof(msg)); 669 } 670 671 672 status_t 673 BMediaRoster::StopNode(const media_node & node, 674 bigtime_t at_performance_time, 675 bool immediate) 676 { 677 CALLED(); 678 if (node.node <= 0) 679 return B_MEDIA_BAD_NODE; 680 681 xfer_node_stop msg; 682 msg.performance_time = at_performance_time; 683 msg.immediate = immediate; 684 685 return write_port(node.port, NODE_STOP, &msg, sizeof(msg)); 686 } 687 688 689 status_t 690 BMediaRoster::SeekNode(const media_node & node, 691 bigtime_t to_media_time, 692 bigtime_t at_performance_time) 693 { 694 CALLED(); 695 if (node.node <= 0) 696 return B_MEDIA_BAD_NODE; 697 698 xfer_node_seek msg; 699 msg.media_time = to_media_time; 700 msg.performance_time = at_performance_time; 701 702 return write_port(node.port, NODE_SEEK, &msg, sizeof(msg)); 703 } 704 705 706 status_t 707 BMediaRoster::StartTimeSource(const media_node & node, 708 bigtime_t at_real_time) 709 { 710 CALLED(); 711 if (node.node <= 0) 712 return B_MEDIA_BAD_NODE; 713 if ((node.kind & B_TIME_SOURCE) == 0) 714 return B_MEDIA_BAD_NODE; 715 716 BTimeSource::time_source_op_info msg; 717 msg.op = BTimeSource::B_TIMESOURCE_START; 718 msg.real_time = at_real_time; 719 720 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 721 } 722 723 724 status_t 725 BMediaRoster::StopTimeSource(const media_node & node, 726 bigtime_t at_real_time, 727 bool immediate) 728 { 729 CALLED(); 730 if (node.node <= 0) 731 return B_MEDIA_BAD_NODE; 732 if ((node.kind & B_TIME_SOURCE) == 0) 733 return B_MEDIA_BAD_NODE; 734 735 BTimeSource::time_source_op_info msg; 736 msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY : BTimeSource::B_TIMESOURCE_STOP; 737 msg.real_time = at_real_time; 738 739 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 740 } 741 742 743 status_t 744 BMediaRoster::SeekTimeSource(const media_node & node, 745 bigtime_t to_performance_time, 746 bigtime_t at_real_time) 747 { 748 CALLED(); 749 if (node.node <= 0) 750 return B_MEDIA_BAD_NODE; 751 if ((node.kind & B_TIME_SOURCE) == 0) 752 return B_MEDIA_BAD_NODE; 753 754 BTimeSource::time_source_op_info msg; 755 msg.op = BTimeSource::B_TIMESOURCE_SEEK; 756 msg.real_time = at_real_time; 757 msg.performance_time = to_performance_time; 758 759 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 760 } 761 762 763 status_t 764 BMediaRoster::SyncToNode(const media_node & node, 765 bigtime_t at_time, 766 bigtime_t timeout) 767 { 768 UNIMPLEMENTED(); 769 return B_ERROR; 770 } 771 772 773 status_t 774 BMediaRoster::SetRunModeNode(const media_node & node, 775 BMediaNode::run_mode mode) 776 { 777 CALLED(); 778 if (node.node <= 0) 779 return B_MEDIA_BAD_NODE; 780 781 xfer_node_set_run_mode msg; 782 msg.mode = mode; 783 784 return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg)); 785 } 786 787 788 status_t 789 BMediaRoster::PrerollNode(const media_node & node) 790 { 791 CALLED(); 792 if (node.node <= 0) 793 return B_MEDIA_BAD_NODE; 794 795 char dummy; 796 return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy)); 797 } 798 799 800 status_t 801 BMediaRoster::RollNode(const media_node & node, 802 bigtime_t startPerformance, 803 bigtime_t stopPerformance, 804 bigtime_t atMediaTime) 805 { 806 UNIMPLEMENTED(); 807 return B_ERROR; 808 } 809 810 811 status_t 812 BMediaRoster::SetProducerRunModeDelay(const media_node & node, 813 bigtime_t delay, 814 BMediaNode::run_mode mode) 815 { 816 UNIMPLEMENTED(); 817 return B_ERROR; 818 } 819 820 821 status_t 822 BMediaRoster::SetProducerRate(const media_node & producer, 823 int32 numer, 824 int32 denom) 825 { 826 CALLED(); 827 if (producer.node == 0) 828 return B_MEDIA_BAD_NODE; 829 if ((producer.kind & B_BUFFER_PRODUCER) == 0) 830 return B_MEDIA_BAD_NODE; 831 832 xfer_producer_set_play_rate msg; 833 xfer_producer_set_play_rate_reply reply; 834 status_t rv; 835 int32 code; 836 837 msg.numer = numer; 838 msg.denom = denom; 839 msg.reply_port = _PortPool->GetPort(); 840 rv = write_port(producer.node, PRODUCER_SET_PLAY_RATE, &msg, sizeof(msg)); 841 if (rv != B_OK) { 842 _PortPool->PutPort(msg.reply_port); 843 return rv; 844 } 845 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 846 _PortPool->PutPort(msg.reply_port); 847 return (rv < B_OK) ? rv : reply.result; 848 } 849 850 851 /* Nodes will have available inputs/outputs as long as they are capable */ 852 /* of accepting more connections. The node may create an additional */ 853 /* output or input as the currently available is taken into usage. */ 854 status_t 855 BMediaRoster::GetLiveNodeInfo(const media_node & node, 856 live_node_info * out_live_info) 857 { 858 CALLED(); 859 if (out_live_info == NULL) 860 return B_BAD_VALUE; 861 if (node.node <= 0) 862 return B_MEDIA_BAD_NODE; 863 864 server_get_live_node_info_request request; 865 server_get_live_node_info_reply reply; 866 status_t rv; 867 868 request.node = node; 869 870 rv = QueryAddonServer(SERVER_GET_LIVE_NODE_INFO, &request, sizeof(request), &reply, sizeof(reply)); 871 if (rv != B_OK) 872 return rv; 873 874 *out_live_info = reply.live_info; 875 return B_OK; 876 } 877 878 879 status_t 880 BMediaRoster::GetLiveNodes(live_node_info * out_live_nodes, 881 int32 * io_total_count, 882 const media_format * has_input, 883 const media_format * has_output, 884 const char * name, 885 uint64 node_kinds) 886 { 887 CALLED(); 888 if (out_live_nodes == NULL || io_total_count == NULL) 889 return B_BAD_VALUE; 890 if (*io_total_count <= 0) 891 return B_BAD_VALUE; 892 893 // XXX we also support the wildcard search as GetDormantNodes does. This needs to be documented 894 895 server_get_live_nodes_request request; 896 server_get_live_nodes_reply reply; 897 status_t rv; 898 899 request.maxcount = *io_total_count; 900 request.has_input = (bool) has_input; 901 if (has_input) 902 request.inputformat = *has_input; // XXX we should not make a flat copy of media_format 903 request.has_output = (bool) has_output; 904 if (has_output) 905 request.outputformat = *has_output; // XXX we should not make a flat copy of media_format 906 request.has_name = (bool) name; 907 if (name) { 908 int len = strlen(name); 909 len = min_c(len, (int)sizeof(request.name) - 1); 910 memcpy(request.name, name, len); 911 request.name[len] = 0; 912 } 913 request.require_kinds = node_kinds; 914 915 rv = QueryServer(SERVER_GET_LIVE_NODES, &request, sizeof(request), &reply, sizeof(reply)); 916 if (rv != B_OK) { 917 TRACE("BMediaRoster::GetLiveNodes failed\n"); 918 return rv; 919 } 920 921 if (reply.count > MAX_LIVE_INFO) { 922 live_node_info *live_info; 923 area_id clone; 924 925 clone = clone_area("live_node_info clone", reinterpret_cast<void **>(&live_info), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, reply.area); 926 if (clone < B_OK) { 927 TRACE("BMediaRoster::GetLiveNodes failed to clone area, %#lx\n", clone); 928 delete_area(reply.area); 929 return B_ERROR; 930 } 931 932 for (int32 i = 0; i < reply.count; i++) { 933 out_live_nodes[i] = live_info[i]; 934 } 935 936 delete_area(clone); 937 delete_area(reply.area); 938 } else { 939 for (int32 i = 0; i < reply.count; i++) { 940 out_live_nodes[i] = reply.live_info[i]; 941 } 942 } 943 *io_total_count = reply.count; 944 945 return B_OK; 946 } 947 948 949 status_t 950 BMediaRoster::GetFreeInputsFor(const media_node & node, 951 media_input * out_free_inputs, 952 int32 buf_num_inputs, 953 int32 * out_total_count, 954 media_type filter_type) 955 { 956 CALLED(); 957 if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 958 return B_MEDIA_BAD_NODE; 959 if (out_free_inputs == NULL || out_total_count == NULL) 960 return B_BAD_VALUE; 961 962 Stack<media_input> stack; 963 media_input *input; 964 status_t rv; 965 966 rv = GetAllInputs(node, &stack); 967 if (B_OK != rv) 968 return rv; 969 970 *out_total_count = 0; 971 for (int32 i = 0; stack.GetPointerAt(i, &input); i++) { 972 if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != input->format.type) 973 continue; // media_type used, but doesn't match 974 if (input->source != media_source::null) 975 continue; // consumer source already connected 976 out_free_inputs[i] = *input; 977 *out_total_count += 1; 978 buf_num_inputs -= 1; 979 if (buf_num_inputs == 0) 980 break; 981 } 982 983 PublishInputs(node, &stack); 984 return B_OK; 985 } 986 987 988 status_t 989 BMediaRoster::GetConnectedInputsFor(const media_node & node, 990 media_input * out_active_inputs, 991 int32 buf_num_inputs, 992 int32 * out_total_count) 993 { 994 CALLED(); 995 if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 996 return B_MEDIA_BAD_NODE; 997 if (out_active_inputs == NULL || out_total_count == NULL) 998 return B_BAD_VALUE; 999 1000 Stack<media_input> stack; 1001 media_input *input; 1002 status_t rv; 1003 1004 rv = GetAllInputs(node, &stack); 1005 if (B_OK != rv) 1006 return rv; 1007 1008 *out_total_count = 0; 1009 for (int32 i = 0; stack.GetPointerAt(i, &input); i++) { 1010 if (input->source == media_source::null) 1011 continue; // consumer source not connected 1012 out_active_inputs[i] = *input; 1013 *out_total_count += 1; 1014 buf_num_inputs -= 1; 1015 if (buf_num_inputs == 0) 1016 break; 1017 } 1018 1019 PublishInputs(node, &stack); 1020 return B_OK; 1021 } 1022 1023 1024 status_t 1025 BMediaRoster::GetAllInputsFor(const media_node & node, 1026 media_input * out_inputs, 1027 int32 buf_num_inputs, 1028 int32 * out_total_count) 1029 { 1030 CALLED(); 1031 if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 1032 return B_MEDIA_BAD_NODE; 1033 if (out_inputs == NULL || out_total_count == NULL) 1034 return B_BAD_VALUE; 1035 1036 Stack<media_input> stack; 1037 media_input *input; 1038 status_t rv; 1039 1040 rv = GetAllInputs(node, &stack); 1041 if (B_OK != rv) 1042 return rv; 1043 1044 *out_total_count = 0; 1045 for (int32 i = 0; stack.GetPointerAt(i, &input); i++) { 1046 out_inputs[i] = *input; 1047 *out_total_count += 1; 1048 buf_num_inputs -= 1; 1049 if (buf_num_inputs == 0) 1050 break; 1051 } 1052 1053 PublishInputs(node, &stack); 1054 return B_OK; 1055 } 1056 1057 1058 status_t 1059 BMediaRoster::GetFreeOutputsFor(const media_node & node, 1060 media_output * out_free_outputs, 1061 int32 buf_num_outputs, 1062 int32 * out_total_count, 1063 media_type filter_type) 1064 { 1065 CALLED(); 1066 if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 1067 return B_MEDIA_BAD_NODE; 1068 if (out_free_outputs == NULL || out_total_count == NULL) 1069 return B_BAD_VALUE; 1070 1071 Stack<media_output> stack; 1072 media_output *output; 1073 status_t rv; 1074 1075 rv = GetAllOutputs(node, &stack); 1076 if (B_OK != rv) 1077 return rv; 1078 1079 *out_total_count = 0; 1080 for (int32 i = 0; stack.GetPointerAt(i, &output); i++) { 1081 if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != output->format.type) 1082 continue; // media_type used, but doesn't match 1083 if (output->destination != media_destination::null) 1084 continue; // producer destination already connected 1085 out_free_outputs[i] = *output; 1086 *out_total_count += 1; 1087 buf_num_outputs -= 1; 1088 if (buf_num_outputs == 0) 1089 break; 1090 } 1091 1092 PublishOutputs(node, &stack); 1093 return B_OK; 1094 } 1095 1096 1097 status_t 1098 BMediaRoster::GetConnectedOutputsFor(const media_node & node, 1099 media_output * out_active_outputs, 1100 int32 buf_num_outputs, 1101 int32 * out_total_count) 1102 { 1103 CALLED(); 1104 if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 1105 return B_MEDIA_BAD_NODE; 1106 if (out_active_outputs == NULL || out_total_count == NULL) 1107 return B_BAD_VALUE; 1108 1109 Stack<media_output> stack; 1110 media_output *output; 1111 status_t rv; 1112 1113 rv = GetAllOutputs(node, &stack); 1114 if (B_OK != rv) 1115 return rv; 1116 1117 *out_total_count = 0; 1118 for (int32 i = 0; stack.GetPointerAt(i, &output); i++) { 1119 if (output->destination == media_destination::null) 1120 continue; // producer destination not connected 1121 out_active_outputs[i] = *output; 1122 *out_total_count += 1; 1123 buf_num_outputs -= 1; 1124 if (buf_num_outputs == 0) 1125 break; 1126 } 1127 1128 PublishOutputs(node, &stack); 1129 return B_OK; 1130 } 1131 1132 1133 status_t 1134 BMediaRoster::GetAllOutputsFor(const media_node & node, 1135 media_output * out_outputs, 1136 int32 buf_num_outputs, 1137 int32 * out_total_count) 1138 { 1139 CALLED(); 1140 if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 1141 return B_MEDIA_BAD_NODE; 1142 if (out_outputs == NULL || out_total_count == NULL) 1143 return B_BAD_VALUE; 1144 1145 Stack<media_output> stack; 1146 media_output *output; 1147 status_t rv; 1148 1149 rv = GetAllOutputs(node, &stack); 1150 if (B_OK != rv) 1151 return rv; 1152 1153 *out_total_count = 0; 1154 for (int32 i = 0; stack.GetPointerAt(i, &output); i++) { 1155 out_outputs[i] = *output; 1156 *out_total_count += 1; 1157 buf_num_outputs -= 1; 1158 if (buf_num_outputs == 0) 1159 break; 1160 } 1161 1162 PublishOutputs(node, &stack); 1163 return B_OK; 1164 } 1165 1166 1167 status_t 1168 BMediaRoster::StartWatching(const BMessenger & where) 1169 { 1170 CALLED(); 1171 if (!where.IsValid()) { 1172 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 1173 return B_BAD_VALUE; 1174 } 1175 return BPrivate::media::notifications::Register(where, media_node::null, B_MEDIA_WILDCARD); 1176 } 1177 1178 1179 status_t 1180 BMediaRoster::StartWatching(const BMessenger & where, 1181 int32 notificationType) 1182 { 1183 CALLED(); 1184 if (!where.IsValid()) { 1185 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 1186 return B_BAD_VALUE; 1187 } 1188 if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) { 1189 TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); 1190 return B_BAD_VALUE; 1191 } 1192 return BPrivate::media::notifications::Register(where, media_node::null, notificationType); 1193 } 1194 1195 1196 status_t 1197 BMediaRoster::StartWatching(const BMessenger & where, 1198 const media_node & node, 1199 int32 notificationType) 1200 { 1201 CALLED(); 1202 if (!where.IsValid()) { 1203 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 1204 return B_BAD_VALUE; 1205 } 1206 if (node.node <= 0) { 1207 TRACE("BMediaRoster::StartWatching: node invalid!\n"); 1208 return B_MEDIA_BAD_NODE; 1209 } 1210 if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) { 1211 TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); 1212 return B_BAD_VALUE; 1213 } 1214 return BPrivate::media::notifications::Register(where, node, notificationType); 1215 } 1216 1217 1218 status_t 1219 BMediaRoster::StopWatching(const BMessenger & where) 1220 { 1221 CALLED(); 1222 // messenger may already be invalid, so we don't check this 1223 return BPrivate::media::notifications::Unregister(where, media_node::null, B_MEDIA_WILDCARD); 1224 } 1225 1226 1227 status_t 1228 BMediaRoster::StopWatching(const BMessenger & where, 1229 int32 notificationType) 1230 { 1231 CALLED(); 1232 // messenger may already be invalid, so we don't check this 1233 if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) { 1234 TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); 1235 return B_BAD_VALUE; 1236 } 1237 return BPrivate::media::notifications::Unregister(where, media_node::null, notificationType); 1238 } 1239 1240 1241 status_t 1242 BMediaRoster::StopWatching(const BMessenger & where, 1243 const media_node & node, 1244 int32 notificationType) 1245 { 1246 CALLED(); 1247 // messenger may already be invalid, so we don't check this 1248 if (node.node <= 0) { 1249 TRACE("BMediaRoster::StopWatching: node invalid!\n"); 1250 return B_MEDIA_BAD_NODE; 1251 } 1252 if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) { 1253 TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); 1254 return B_BAD_VALUE; 1255 } 1256 return BPrivate::media::notifications::Unregister(where, node, notificationType); 1257 } 1258 1259 1260 status_t 1261 BMediaRoster::RegisterNode(BMediaNode * node) 1262 { 1263 CALLED(); 1264 if (node == NULL) 1265 return B_BAD_VALUE; 1266 1267 status_t rv; 1268 BMediaAddOn *addon; 1269 int32 addon_flavor_id; 1270 media_addon_id addon_id; 1271 1272 addon_flavor_id = 0; 1273 addon = node->AddOn(&addon_flavor_id); 1274 addon_id = addon ? addon->AddonID() : -1; 1275 1276 server_register_node_request request; 1277 server_register_node_reply reply; 1278 1279 request.addon_id = addon_id; 1280 request.addon_flavor_id = addon_flavor_id; 1281 strcpy(request.name, node->Name()); 1282 request.kinds = node->Kinds(); 1283 request.port = node->ControlPort(); 1284 request.team = team; 1285 1286 rv = QueryServer(SERVER_REGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1287 if (rv != B_OK) { 1288 TRACE("BMediaRoster::RegisterNode: failed to register node %s (error %#lx)\n", node->Name(), rv); 1289 return rv; 1290 } 1291 1292 // we are a friend class of BMediaNode and initilize this member variable 1293 node->fNodeID = reply.nodeid; 1294 ASSERT(reply.nodeid == node->Node().node); 1295 ASSERT(reply.nodeid == node->ID()); 1296 1297 // call the callback 1298 node->NodeRegistered(); 1299 1300 // register existing inputs and outputs with the 1301 // media_server, this allows GetLiveNodes() to work 1302 // with created, but unconnected nodes. 1303 if (node->Kinds() & B_BUFFER_PRODUCER) { 1304 Stack<media_output> stack; 1305 if (B_OK == GetAllOutputs(node->Node(), &stack)) 1306 PublishOutputs(node->Node(), &stack); 1307 } else if (node->Kinds() & B_BUFFER_CONSUMER) { 1308 Stack<media_input> stack; 1309 if (B_OK == GetAllInputs(node->Node(), &stack)) 1310 PublishInputs(node->Node(), &stack); 1311 } 1312 1313 TRACE("BMediaRoster::RegisterNode: registered node %s, id %ld, addon %ld, flavor %ld\n", node->Name(), node->ID(), addon_id, addon_flavor_id); 1314 1315 return B_OK; 1316 } 1317 1318 1319 status_t 1320 BMediaRoster::UnregisterNode(BMediaNode * node) 1321 { 1322 CALLED(); 1323 if (node == NULL) 1324 return B_BAD_VALUE; 1325 1326 if (node->fRefCount != 0) { 1327 TRACE("BMediaRoster::UnregisterNode: Warning node %s has local reference count of %ld\n", node->Name(), node->fRefCount); 1328 // no return here, we continue and unregister! 1329 } 1330 if (node->ID() == -2) { 1331 TRACE("BMediaRoster::UnregisterNode: Warning node %s already unregistered\n", node->Name()); 1332 return B_OK; 1333 } 1334 1335 server_unregister_node_request request; 1336 server_unregister_node_reply reply; 1337 status_t rv; 1338 1339 request.nodeid = node->ID(); 1340 request.team = team; 1341 1342 rv = QueryServer(SERVER_UNREGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1343 if (rv != B_OK) { 1344 TRACE("BMediaRoster::UnregisterNode: failed to unregister node %s (error %#lx)\n", node->Name(), rv); 1345 return rv; 1346 } 1347 1348 if (reply.addon_id != -1) 1349 _DormantNodeManager->PutAddon(reply.addon_id); 1350 1351 // we are a friend class of BMediaNode and initilize this member variable 1352 node->fNodeID = -2; 1353 1354 return B_OK; 1355 } 1356 1357 1358 // thread safe for multiple calls to Roster() 1359 /* static */ BMediaRoster * 1360 BMediaRoster::Roster(status_t* out_error) 1361 { 1362 CALLED(); 1363 static BLocker locker("BMediaRoster::Roster locker"); 1364 locker.Lock(); 1365 if (_sDefault == NULL) { 1366 _sDefault = new BMediaRoster(); 1367 if (out_error != NULL) 1368 *out_error = B_OK; 1369 } else { 1370 if (out_error != NULL) 1371 *out_error = B_OK; 1372 } 1373 locker.Unlock(); 1374 return _sDefault; 1375 } 1376 1377 1378 // won't create it if there isn't one 1379 // not thread safe if you call Roster() at the same time 1380 /* static */ BMediaRoster * 1381 BMediaRoster::CurrentRoster() 1382 { 1383 CALLED(); 1384 return _sDefault; 1385 } 1386 1387 1388 status_t 1389 BMediaRoster::SetTimeSourceFor(media_node_id node, 1390 media_node_id time_source) 1391 { 1392 UNIMPLEMENTED(); 1393 return B_ERROR; 1394 } 1395 1396 1397 status_t 1398 BMediaRoster::GetParameterWebFor(const media_node & node, 1399 BParameterWeb ** out_web) 1400 { 1401 UNIMPLEMENTED(); 1402 return B_ERROR; 1403 } 1404 1405 1406 status_t 1407 BMediaRoster::StartControlPanel(const media_node & node, 1408 BMessenger * out_messenger) 1409 { 1410 UNIMPLEMENTED(); 1411 return B_ERROR; 1412 } 1413 1414 1415 status_t 1416 BMediaRoster::GetDormantNodes(dormant_node_info * out_info, 1417 int32 * io_count, 1418 const media_format * has_input /* = NULL */, 1419 const media_format * has_output /* = NULL */, 1420 const char * name /* = NULL */, 1421 uint64 require_kinds /* = NULL */, 1422 uint64 deny_kinds /* = NULL */) 1423 { 1424 CALLED(); 1425 if (out_info == NULL) 1426 return B_BAD_VALUE; 1427 if (io_count == NULL) 1428 return B_BAD_VALUE; 1429 if (*io_count <= 0) 1430 return B_BAD_VALUE; 1431 1432 xfer_server_get_dormant_nodes msg; 1433 port_id port; 1434 status_t rv; 1435 1436 port = find_port("media_server port"); 1437 if (port <= B_OK) 1438 return B_ERROR; 1439 1440 msg.maxcount = *io_count; 1441 msg.has_input = (bool) has_input; 1442 if (has_input) 1443 msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format 1444 msg.has_output = (bool) has_output; 1445 if (has_output) 1446 msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format 1447 msg.has_name = (bool) name; 1448 if (name) { 1449 int len = strlen(name); 1450 len = min_c(len, (int)sizeof(msg.name) - 1); 1451 memcpy(msg.name, name, len); 1452 msg.name[len] = 0; 1453 } 1454 msg.require_kinds = require_kinds; 1455 msg.deny_kinds = deny_kinds; 1456 msg.reply_port = _PortPool->GetPort(); 1457 1458 rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg)); 1459 if (rv != B_OK) { 1460 _PortPool->PutPort(msg.reply_port); 1461 return rv; 1462 } 1463 1464 xfer_server_get_dormant_nodes_reply reply; 1465 int32 code; 1466 1467 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 1468 if (rv < B_OK) { 1469 _PortPool->PutPort(msg.reply_port); 1470 return rv; 1471 } 1472 1473 *io_count = reply.count; 1474 1475 if (*io_count > 0) { 1476 rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info)); 1477 if (rv < B_OK) 1478 reply.result = rv; 1479 } 1480 _PortPool->PutPort(msg.reply_port); 1481 1482 return reply.result; 1483 } 1484 1485 1486 status_t 1487 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, 1488 media_node * out_node, 1489 uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ ) 1490 { 1491 CALLED(); 1492 if ((flags & (B_FLAVOR_IS_GLOBAL | B_FLAVOR_IS_LOCAL)) == 0) { 1493 printf("Error: BMediaRoster::InstantiateDormantNode called without flags\n"); 1494 return B_BAD_VALUE; 1495 } 1496 if (out_node == 0) 1497 return B_BAD_VALUE; 1498 1499 // XXX we should not trust the values passed in by the user, 1500 // XXX and ask the server to determine where to insta 1501 1502 1503 // XXX SOMETHING IS VERY WRONG HERE 1504 // if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) == 0 && (flags & B_FLAVOR_IS_LOCAL)) { 1505 if (flags & B_FLAVOR_IS_LOCAL) { 1506 return InstantiateDormantNode(in_info,out_node); 1507 } 1508 1509 // XXX SOMETHING IS VERY WRONG HERE 1510 // if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) { 1511 if (flags & B_FLAVOR_IS_GLOBAL) { 1512 // forward this request into the media_addon_server, 1513 // which in turn will call InstantiateDormantNode() 1514 // to create it there localy 1515 addonserver_instantiate_dormant_node_request request; 1516 addonserver_instantiate_dormant_node_reply reply; 1517 status_t rv; 1518 1519 request.info = in_info; 1520 rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1521 if (rv == B_OK) { 1522 *out_node = reply.node; 1523 } 1524 return rv; 1525 } 1526 1527 // XXX SOMETHING IS VERY WRONG HERE 1528 printf("Error: BMediaRoster::InstantiateDormantNode addon_id %d, flavor_id %d, flags %#08lx\n", (int)in_info.addon, (int)in_info.flavor_id, flags); 1529 1530 return B_ERROR; 1531 } 1532 1533 1534 status_t 1535 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, 1536 media_node * out_node) 1537 { 1538 CALLED(); 1539 1540 // to instantiate a dormant node in the current address space, we need to 1541 // either load the add-on from file and create a new BMediaAddOn class, or 1542 // reuse the cached BMediaAddOn from a previous call 1543 // call BMediaAddOn::InstantiateNodeFor() 1544 // and cache the BMediaAddOn after that for later reuse. 1545 // BeOS R5 does not seem to delete it when the application quits 1546 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that 1547 // resides in the media_addon_server 1548 1549 // RegisterNode() is called automatically for nodes instantiated from add-ons 1550 1551 //XXX TEST! 1552 BMediaAddOn *addon; 1553 BMediaNode *node; 1554 BMessage config; 1555 status_t out_error; 1556 status_t rv; 1557 addon = _DormantNodeManager->GetAddon(in_info.addon); 1558 if (!addon) { 1559 printf("BMediaRoster::InstantiateDormantNode: GetAddon failed\n"); 1560 return B_ERROR; 1561 } 1562 flavor_info temp; 1563 temp.internal_id = in_info.flavor_id; 1564 node = addon->InstantiateNodeFor(&temp, &config, &out_error); 1565 if (!node) { 1566 printf("BMediaRoster::InstantiateDormantNode: InstantiateNodeFor failed\n"); 1567 _DormantNodeManager->PutAddon(in_info.addon); 1568 return B_ERROR; 1569 } 1570 rv = RegisterNode(node); 1571 if (rv != B_OK) { 1572 printf("BMediaRoster::InstantiateDormantNode: RegisterNode failed\n"); 1573 delete node; 1574 _DormantNodeManager->PutAddon(in_info.addon); 1575 return B_ERROR; 1576 } 1577 1578 // XXX we must remember in_info.addon and call 1579 // XXX _DormantNodeManager->PutAddon when the 1580 // XXX node is unregistered 1581 // should be handled by RegisterNode() and UnegisterNode() now 1582 1583 *out_node = node->Node(); 1584 return B_OK; 1585 } 1586 1587 1588 status_t 1589 BMediaRoster::GetDormantNodeFor(const media_node & node, 1590 dormant_node_info * out_info) 1591 { 1592 CALLED(); 1593 if (out_info == NULL) 1594 return B_BAD_VALUE; 1595 if (node.node <= 0) 1596 return B_MEDIA_BAD_NODE; 1597 1598 server_get_dormant_node_for_request request; 1599 server_get_dormant_node_for_reply reply; 1600 status_t rv; 1601 1602 request.node = node; 1603 1604 rv = QueryAddonServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply)); 1605 if (rv != B_OK) 1606 return rv; 1607 1608 *out_info = reply.node_info; 1609 return B_OK; 1610 } 1611 1612 1613 status_t 1614 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant, 1615 dormant_flavor_info * out_flavor) 1616 { 1617 CALLED(); 1618 1619 xfer_server_get_dormant_flavor_info msg; 1620 xfer_server_get_dormant_flavor_info_reply *reply; 1621 port_id port; 1622 status_t rv; 1623 int32 code; 1624 1625 port = find_port("media_server port"); 1626 if (port <= B_OK) 1627 return B_ERROR; 1628 1629 reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000); 1630 if (reply == 0) 1631 return B_ERROR; 1632 1633 msg.addon = in_dormant.addon; 1634 msg.flavor_id = in_dormant.flavor_id; 1635 msg.reply_port = _PortPool->GetPort(); 1636 rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg)); 1637 if (rv != B_OK) { 1638 free(reply); 1639 _PortPool->PutPort(msg.reply_port); 1640 return rv; 1641 } 1642 rv = read_port(msg.reply_port, &code, reply, 16000); 1643 _PortPool->PutPort(msg.reply_port); 1644 1645 if (rv < B_OK) { 1646 free(reply); 1647 return rv; 1648 } 1649 1650 if (reply->result == B_OK) 1651 rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size); 1652 else 1653 rv = reply->result; 1654 1655 free(reply); 1656 return rv; 1657 } 1658 1659 1660 status_t 1661 BMediaRoster::GetLatencyFor(const media_node & producer, 1662 bigtime_t * out_latency) 1663 { 1664 UNIMPLEMENTED(); 1665 *out_latency = 0; 1666 return B_ERROR; 1667 } 1668 1669 1670 status_t 1671 BMediaRoster::GetInitialLatencyFor(const media_node & producer, 1672 bigtime_t * out_latency, 1673 uint32 * out_flags) 1674 { 1675 UNIMPLEMENTED(); 1676 *out_latency = 0; 1677 *out_flags = 0; 1678 return B_ERROR; 1679 } 1680 1681 1682 status_t 1683 BMediaRoster::GetStartLatencyFor(const media_node & time_source, 1684 bigtime_t * out_latency) 1685 { 1686 UNIMPLEMENTED(); 1687 *out_latency = 0; 1688 return B_ERROR; 1689 } 1690 1691 1692 status_t 1693 BMediaRoster::GetFileFormatsFor(const media_node & file_interface, 1694 media_file_format * out_formats, 1695 int32 * io_num_infos) 1696 { 1697 UNIMPLEMENTED(); 1698 return B_ERROR; 1699 } 1700 1701 1702 status_t 1703 BMediaRoster::SetRefFor(const media_node & file_interface, 1704 const entry_ref & file, 1705 bool create_and_truncate, 1706 bigtime_t * out_length) /* if create is false */ 1707 { 1708 UNIMPLEMENTED(); 1709 return B_ERROR; 1710 } 1711 1712 1713 status_t 1714 BMediaRoster::GetRefFor(const media_node & node, 1715 entry_ref * out_file, 1716 BMimeType * mime_type) 1717 { 1718 UNIMPLEMENTED(); 1719 return B_ERROR; 1720 } 1721 1722 1723 status_t 1724 BMediaRoster::SniffRefFor(const media_node & file_interface, 1725 const entry_ref & file, 1726 BMimeType * mime_type, 1727 float * out_capability) 1728 { 1729 UNIMPLEMENTED(); 1730 return B_ERROR; 1731 } 1732 1733 1734 /* This is the generic "here's a file, now can someone please play it" interface */ 1735 status_t 1736 BMediaRoster::SniffRef(const entry_ref & file, 1737 uint64 require_node_kinds, /* if you need an EntityInterface or BufferConsumer or something */ 1738 dormant_node_info * out_node, 1739 BMimeType * mime_type) 1740 { 1741 UNIMPLEMENTED(); 1742 return B_ERROR; 1743 } 1744 1745 1746 status_t 1747 BMediaRoster::GetDormantNodeForType(const BMimeType & type, 1748 uint64 require_node_kinds, 1749 dormant_node_info * out_node) 1750 { 1751 UNIMPLEMENTED(); 1752 return B_ERROR; 1753 } 1754 1755 1756 status_t 1757 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node, 1758 media_file_format * out_read_formats, 1759 int32 in_read_count, 1760 int32 * out_read_count) 1761 { 1762 UNIMPLEMENTED(); 1763 return B_ERROR; 1764 } 1765 1766 1767 status_t 1768 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node, 1769 media_file_format * out_write_formats, 1770 int32 in_write_count, 1771 int32 * out_write_count) 1772 { 1773 UNIMPLEMENTED(); 1774 return B_ERROR; 1775 } 1776 1777 1778 status_t 1779 BMediaRoster::GetFormatFor(const media_output & output, 1780 media_format * io_format, 1781 uint32 flags) 1782 { 1783 UNIMPLEMENTED(); 1784 return B_ERROR; 1785 } 1786 1787 1788 status_t 1789 BMediaRoster::GetFormatFor(const media_input & input, 1790 media_format * io_format, 1791 uint32 flags) 1792 { 1793 UNIMPLEMENTED(); 1794 return B_ERROR; 1795 } 1796 1797 1798 status_t 1799 BMediaRoster::GetFormatFor(const media_node & node, 1800 media_format * io_format, 1801 float quality) 1802 { 1803 UNIMPLEMENTED(); 1804 return B_ERROR; 1805 } 1806 1807 1808 ssize_t 1809 BMediaRoster::GetNodeAttributesFor(const media_node & node, 1810 media_node_attribute * outArray, 1811 size_t inMaxCount) 1812 { 1813 UNIMPLEMENTED(); 1814 return B_ERROR; 1815 } 1816 1817 1818 media_node_id 1819 BMediaRoster::NodeIDFor(port_id source_or_destination_port) 1820 { 1821 CALLED(); 1822 1823 server_node_id_for_request request; 1824 server_node_id_for_reply reply; 1825 status_t rv; 1826 1827 request.port = source_or_destination_port; 1828 1829 rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply, sizeof(reply)); 1830 if (rv != B_OK) { 1831 TRACE("BMediaRoster::NodeIDFor: failed (error %#lx)\n", rv); 1832 return -1; 1833 } 1834 1835 return reply.nodeid; 1836 } 1837 1838 1839 status_t 1840 BMediaRoster::GetInstancesFor(media_addon_id addon, 1841 int32 flavor, 1842 media_node_id * out_id, 1843 int32 * io_count) 1844 { 1845 CALLED(); 1846 if (out_id == NULL || io_count == NULL) 1847 return B_BAD_VALUE; 1848 if (*io_count <= 0) 1849 return B_BAD_VALUE; 1850 1851 server_get_instances_for_request request; 1852 server_get_instances_for_reply reply; 1853 status_t rv; 1854 1855 request.maxcount = *io_count; 1856 request.addon_id = addon; 1857 request.addon_flavor_id = flavor; 1858 1859 rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request), &reply, sizeof(reply)); 1860 if (rv != B_OK) { 1861 TRACE("BMediaRoster::GetLiveNodes failed\n"); 1862 return rv; 1863 } 1864 1865 *io_count = reply.count; 1866 if (reply.count > 0) 1867 memcpy(out_id, reply.node_id, sizeof(media_node_id) * reply.count); 1868 1869 return B_OK; 1870 } 1871 1872 1873 status_t 1874 BMediaRoster::SetRealtimeFlags(uint32 in_enabled) 1875 { 1876 UNIMPLEMENTED(); 1877 return B_ERROR; 1878 } 1879 1880 1881 status_t 1882 BMediaRoster::GetRealtimeFlags(uint32 * out_enabled) 1883 { 1884 UNIMPLEMENTED(); 1885 return B_ERROR; 1886 } 1887 1888 1889 ssize_t 1890 BMediaRoster::AudioBufferSizeFor(int32 channel_count, 1891 uint32 sample_format, 1892 float frame_rate, 1893 bus_type bus_kind) 1894 { 1895 UNIMPLEMENTED(); 1896 return 4096; 1897 } 1898 1899 1900 /* Use MediaFlags to inquire about specific features of the Media Kit. */ 1901 /* Returns < 0 for "not present", positive size for output data size. */ 1902 /* 0 means that the capability is present, but no data about it. */ 1903 /* static */ ssize_t 1904 BMediaRoster::MediaFlags(media_flags cap, 1905 void * buf, 1906 size_t maxSize) 1907 { 1908 UNIMPLEMENTED(); 1909 return 0; 1910 } 1911 1912 1913 1914 /* BLooper overrides */ 1915 /* virtual */ void 1916 BMediaRoster::MessageReceived(BMessage * message) 1917 { 1918 UNIMPLEMENTED(); 1919 } 1920 1921 /* virtual */ bool 1922 BMediaRoster::QuitRequested() 1923 { 1924 UNIMPLEMENTED(); 1925 return true; 1926 } 1927 1928 /* virtual */ BHandler * 1929 BMediaRoster::ResolveSpecifier(BMessage *msg, 1930 int32 index, 1931 BMessage *specifier, 1932 int32 form, 1933 const char *property) 1934 { 1935 UNIMPLEMENTED(); 1936 return 0; 1937 } 1938 1939 1940 /* virtual */ status_t 1941 BMediaRoster::GetSupportedSuites(BMessage *data) 1942 { 1943 UNIMPLEMENTED(); 1944 return B_ERROR; 1945 } 1946 1947 1948 BMediaRoster::~BMediaRoster() 1949 { 1950 CALLED(); 1951 BMessage msg(MEDIA_SERVER_UNREGISTER_APP); 1952 BMessage reply; 1953 msg.AddInt32("team",team); 1954 QueryServer(&msg, &reply); 1955 } 1956 1957 1958 /************************************************************* 1959 * private BMediaRoster 1960 *************************************************************/ 1961 1962 // deprecated call 1963 status_t 1964 BMediaRoster::SetOutputBuffersFor(const media_source & output, 1965 BBufferGroup * group, 1966 bool will_reclaim ) 1967 { 1968 UNIMPLEMENTED(); 1969 debugger("BMediaRoster::SetOutputBuffersFor missing\n"); 1970 return B_ERROR; 1971 } 1972 1973 1974 /* FBC stuffing (Mmmh, Stuffing!) */ 1975 status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; } 1976 status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; } 1977 status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; } 1978 status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; } 1979 status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; } 1980 status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; } 1981 status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; } 1982 status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; } 1983 1984 1985 BMediaRoster::BMediaRoster() : 1986 BLooper("BMediaRoster looper",B_NORMAL_PRIORITY,B_LOOPER_PORT_DEFAULT_CAPACITY) 1987 { 1988 CALLED(); 1989 BMessage msg(MEDIA_SERVER_REGISTER_APP); 1990 BMessage reply; 1991 msg.AddInt32("team",team); 1992 QueryServer(&msg,&reply); 1993 } 1994 1995 /* static */ status_t 1996 BMediaRoster::ParseCommand(BMessage & reply) 1997 { 1998 UNIMPLEMENTED(); 1999 return B_ERROR; 2000 } 2001 2002 2003 2004 status_t 2005 BMediaRoster::GetDefaultInfo(media_node_id for_default, 2006 BMessage & out_config) 2007 { 2008 UNIMPLEMENTED(); 2009 return B_ERROR; 2010 } 2011 2012 2013 2014 status_t 2015 BMediaRoster::SetRunningDefault(media_node_id for_default, 2016 const media_node & node) 2017 { 2018 UNIMPLEMENTED(); 2019 return B_ERROR; 2020 } 2021 2022 2023 /************************************************************* 2024 * static BMediaRoster variables 2025 *************************************************************/ 2026 2027 bool BMediaRoster::_isMediaServer; 2028 port_id BMediaRoster::_mReplyPort; 2029 int32 BMediaRoster::_mReplyPortRes; 2030 int32 BMediaRoster::_mReplyPortUnavailCount; 2031 BMediaRoster * BMediaRoster::_sDefault = NULL; 2032 2033