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 #define DEBUG 3 15 #include <Debug.h> 16 #include "debug.h" 17 #include "TStack.h" 18 #include "PortPool.h" 19 #include "SystemTimeSource.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 BROKEN(); 436 return new _SysTimeSource(); // XXX fix this 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 node_start_command 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 node_stop_command 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 node_seek_command 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 node_set_run_mode_command 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 producer_set_play_rate_request msg; 833 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 = QueryServer(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 *io_total_count = 0; 919 return rv; 920 } 921 922 if (reply.count > MAX_LIVE_INFO) { 923 live_node_info *live_info; 924 area_id clone; 925 926 clone = clone_area("live_node_info clone", reinterpret_cast<void **>(&live_info), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, reply.area); 927 if (clone < B_OK) { 928 TRACE("BMediaRoster::GetLiveNodes failed to clone area, %#lx\n", clone); 929 delete_area(reply.area); 930 *io_total_count = 0; 931 return B_ERROR; 932 } 933 934 for (int32 i = 0; i < reply.count; i++) { 935 out_live_nodes[i] = live_info[i]; 936 } 937 938 delete_area(clone); 939 delete_area(reply.area); 940 } else { 941 for (int32 i = 0; i < reply.count; i++) { 942 out_live_nodes[i] = reply.live_info[i]; 943 } 944 } 945 *io_total_count = reply.count; 946 947 return B_OK; 948 } 949 950 951 status_t 952 BMediaRoster::GetFreeInputsFor(const media_node & node, 953 media_input * out_free_inputs, 954 int32 buf_num_inputs, 955 int32 * out_total_count, 956 media_type filter_type) 957 { 958 CALLED(); 959 if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 960 return B_MEDIA_BAD_NODE; 961 if (out_free_inputs == NULL || out_total_count == NULL) 962 return B_BAD_VALUE; 963 964 Stack<media_input> stack; 965 media_input *input; 966 status_t rv; 967 968 *out_total_count = 0; 969 970 rv = GetAllInputs(node, &stack); 971 if (B_OK != rv) 972 return rv; 973 974 for (int32 i = 0; stack.GetPointerAt(i, &input); i++) { 975 if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != input->format.type) 976 continue; // media_type used, but doesn't match 977 if (input->source != media_source::null) 978 continue; // consumer source already connected 979 out_free_inputs[i] = *input; 980 *out_total_count += 1; 981 buf_num_inputs -= 1; 982 if (buf_num_inputs == 0) 983 break; 984 } 985 986 PublishInputs(node, &stack); 987 return B_OK; 988 } 989 990 991 status_t 992 BMediaRoster::GetConnectedInputsFor(const media_node & node, 993 media_input * out_active_inputs, 994 int32 buf_num_inputs, 995 int32 * out_total_count) 996 { 997 CALLED(); 998 if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 999 return B_MEDIA_BAD_NODE; 1000 if (out_active_inputs == NULL || out_total_count == NULL) 1001 return B_BAD_VALUE; 1002 1003 Stack<media_input> stack; 1004 media_input *input; 1005 status_t rv; 1006 1007 *out_total_count = 0; 1008 1009 rv = GetAllInputs(node, &stack); 1010 if (B_OK != rv) 1011 return rv; 1012 1013 for (int32 i = 0; stack.GetPointerAt(i, &input); i++) { 1014 if (input->source == media_source::null) 1015 continue; // consumer source not connected 1016 out_active_inputs[i] = *input; 1017 *out_total_count += 1; 1018 buf_num_inputs -= 1; 1019 if (buf_num_inputs == 0) 1020 break; 1021 } 1022 1023 PublishInputs(node, &stack); 1024 return B_OK; 1025 } 1026 1027 1028 status_t 1029 BMediaRoster::GetAllInputsFor(const media_node & node, 1030 media_input * out_inputs, 1031 int32 buf_num_inputs, 1032 int32 * out_total_count) 1033 { 1034 CALLED(); 1035 if (node.node <= 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 1036 return B_MEDIA_BAD_NODE; 1037 if (out_inputs == NULL || out_total_count == NULL) 1038 return B_BAD_VALUE; 1039 1040 Stack<media_input> stack; 1041 media_input *input; 1042 status_t rv; 1043 1044 *out_total_count = 0; 1045 1046 rv = GetAllInputs(node, &stack); 1047 if (B_OK != rv) 1048 return rv; 1049 1050 for (int32 i = 0; stack.GetPointerAt(i, &input); i++) { 1051 out_inputs[i] = *input; 1052 *out_total_count += 1; 1053 buf_num_inputs -= 1; 1054 if (buf_num_inputs == 0) 1055 break; 1056 } 1057 1058 PublishInputs(node, &stack); 1059 return B_OK; 1060 } 1061 1062 1063 status_t 1064 BMediaRoster::GetFreeOutputsFor(const media_node & node, 1065 media_output * out_free_outputs, 1066 int32 buf_num_outputs, 1067 int32 * out_total_count, 1068 media_type filter_type) 1069 { 1070 CALLED(); 1071 if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 1072 return B_MEDIA_BAD_NODE; 1073 if (out_free_outputs == NULL || out_total_count == NULL) 1074 return B_BAD_VALUE; 1075 1076 Stack<media_output> stack; 1077 media_output *output; 1078 status_t rv; 1079 1080 *out_total_count = 0; 1081 1082 rv = GetAllOutputs(node, &stack); 1083 if (B_OK != rv) 1084 return rv; 1085 1086 for (int32 i = 0; stack.GetPointerAt(i, &output); i++) { 1087 if (filter_type != B_MEDIA_UNKNOWN_TYPE && filter_type != output->format.type) 1088 continue; // media_type used, but doesn't match 1089 if (output->destination != media_destination::null) 1090 continue; // producer destination already connected 1091 out_free_outputs[i] = *output; 1092 *out_total_count += 1; 1093 buf_num_outputs -= 1; 1094 if (buf_num_outputs == 0) 1095 break; 1096 } 1097 1098 PublishOutputs(node, &stack); 1099 return B_OK; 1100 } 1101 1102 1103 status_t 1104 BMediaRoster::GetConnectedOutputsFor(const media_node & node, 1105 media_output * out_active_outputs, 1106 int32 buf_num_outputs, 1107 int32 * out_total_count) 1108 { 1109 CALLED(); 1110 if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 1111 return B_MEDIA_BAD_NODE; 1112 if (out_active_outputs == NULL || out_total_count == NULL) 1113 return B_BAD_VALUE; 1114 1115 Stack<media_output> stack; 1116 media_output *output; 1117 status_t rv; 1118 1119 *out_total_count = 0; 1120 1121 rv = GetAllOutputs(node, &stack); 1122 if (B_OK != rv) 1123 return rv; 1124 1125 for (int32 i = 0; stack.GetPointerAt(i, &output); i++) { 1126 if (output->destination == media_destination::null) 1127 continue; // producer destination not connected 1128 out_active_outputs[i] = *output; 1129 *out_total_count += 1; 1130 buf_num_outputs -= 1; 1131 if (buf_num_outputs == 0) 1132 break; 1133 } 1134 1135 PublishOutputs(node, &stack); 1136 return B_OK; 1137 } 1138 1139 1140 status_t 1141 BMediaRoster::GetAllOutputsFor(const media_node & node, 1142 media_output * out_outputs, 1143 int32 buf_num_outputs, 1144 int32 * out_total_count) 1145 { 1146 CALLED(); 1147 if (node.node <= 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 1148 return B_MEDIA_BAD_NODE; 1149 if (out_outputs == NULL || out_total_count == NULL) 1150 return B_BAD_VALUE; 1151 1152 Stack<media_output> stack; 1153 media_output *output; 1154 status_t rv; 1155 1156 *out_total_count = 0; 1157 1158 rv = GetAllOutputs(node, &stack); 1159 if (B_OK != rv) 1160 return rv; 1161 1162 for (int32 i = 0; stack.GetPointerAt(i, &output); i++) { 1163 out_outputs[i] = *output; 1164 *out_total_count += 1; 1165 buf_num_outputs -= 1; 1166 if (buf_num_outputs == 0) 1167 break; 1168 } 1169 1170 PublishOutputs(node, &stack); 1171 return B_OK; 1172 } 1173 1174 1175 status_t 1176 BMediaRoster::StartWatching(const BMessenger & where) 1177 { 1178 CALLED(); 1179 if (!where.IsValid()) { 1180 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 1181 return B_BAD_VALUE; 1182 } 1183 return BPrivate::media::notifications::Register(where, media_node::null, B_MEDIA_WILDCARD); 1184 } 1185 1186 1187 status_t 1188 BMediaRoster::StartWatching(const BMessenger & where, 1189 int32 notificationType) 1190 { 1191 CALLED(); 1192 if (!where.IsValid()) { 1193 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 1194 return B_BAD_VALUE; 1195 } 1196 if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) { 1197 TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); 1198 return B_BAD_VALUE; 1199 } 1200 return BPrivate::media::notifications::Register(where, media_node::null, notificationType); 1201 } 1202 1203 1204 status_t 1205 BMediaRoster::StartWatching(const BMessenger & where, 1206 const media_node & node, 1207 int32 notificationType) 1208 { 1209 CALLED(); 1210 if (!where.IsValid()) { 1211 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 1212 return B_BAD_VALUE; 1213 } 1214 if (node.node <= 0) { 1215 TRACE("BMediaRoster::StartWatching: node invalid!\n"); 1216 return B_MEDIA_BAD_NODE; 1217 } 1218 if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) { 1219 TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); 1220 return B_BAD_VALUE; 1221 } 1222 return BPrivate::media::notifications::Register(where, node, notificationType); 1223 } 1224 1225 1226 status_t 1227 BMediaRoster::StopWatching(const BMessenger & where) 1228 { 1229 CALLED(); 1230 // messenger may already be invalid, so we don't check this 1231 return BPrivate::media::notifications::Unregister(where, media_node::null, B_MEDIA_WILDCARD); 1232 } 1233 1234 1235 status_t 1236 BMediaRoster::StopWatching(const BMessenger & where, 1237 int32 notificationType) 1238 { 1239 CALLED(); 1240 // messenger may already be invalid, so we don't check this 1241 if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) { 1242 TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); 1243 return B_BAD_VALUE; 1244 } 1245 return BPrivate::media::notifications::Unregister(where, media_node::null, notificationType); 1246 } 1247 1248 1249 status_t 1250 BMediaRoster::StopWatching(const BMessenger & where, 1251 const media_node & node, 1252 int32 notificationType) 1253 { 1254 CALLED(); 1255 // messenger may already be invalid, so we don't check this 1256 if (node.node <= 0) { 1257 TRACE("BMediaRoster::StopWatching: node invalid!\n"); 1258 return B_MEDIA_BAD_NODE; 1259 } 1260 if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) { 1261 TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); 1262 return B_BAD_VALUE; 1263 } 1264 return BPrivate::media::notifications::Unregister(where, node, notificationType); 1265 } 1266 1267 1268 status_t 1269 BMediaRoster::RegisterNode(BMediaNode * node) 1270 { 1271 CALLED(); 1272 if (node == NULL) 1273 return B_BAD_VALUE; 1274 1275 status_t rv; 1276 BMediaAddOn *addon; 1277 int32 addon_flavor_id; 1278 media_addon_id addon_id; 1279 1280 addon_flavor_id = 0; 1281 addon = node->AddOn(&addon_flavor_id); 1282 addon_id = addon ? addon->AddonID() : -1; 1283 1284 server_register_node_request request; 1285 server_register_node_reply reply; 1286 1287 request.addon_id = addon_id; 1288 request.addon_flavor_id = addon_flavor_id; 1289 strcpy(request.name, node->Name()); 1290 request.kinds = node->Kinds(); 1291 request.port = node->ControlPort(); 1292 request.team = team; 1293 1294 TRACE("BMediaRoster::RegisterNode: sending SERVER_REGISTER_NODE: port %ld, kinds %#Lx, team %ld, name '%s'\n", request.port, request.kinds, request.team, request.name); 1295 1296 rv = QueryServer(SERVER_REGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1297 if (rv != B_OK) { 1298 TRACE("BMediaRoster::RegisterNode: failed to register node %s (error %#lx)\n", node->Name(), rv); 1299 return rv; 1300 } 1301 1302 // we are a friend class of BMediaNode and initilize this member variable 1303 node->fNodeID = reply.nodeid; 1304 ASSERT(reply.nodeid == node->Node().node); 1305 ASSERT(reply.nodeid == node->ID()); 1306 1307 // call the callback 1308 node->NodeRegistered(); 1309 1310 /* 1311 // register existing inputs and outputs with the 1312 // media_server, this allows GetLiveNodes() to work 1313 // with created, but unconnected nodes. 1314 if (node->Kinds() & B_BUFFER_PRODUCER) { 1315 Stack<media_output> stack; 1316 if (B_OK == GetAllOutputs(node->Node(), &stack)) 1317 PublishOutputs(node->Node(), &stack); 1318 } else if (node->Kinds() & B_BUFFER_CONSUMER) { 1319 Stack<media_input> stack; 1320 if (B_OK == GetAllInputs(node->Node(), &stack)) 1321 PublishInputs(node->Node(), &stack); 1322 } 1323 */ 1324 1325 BPrivate::media::notifications::NodesCreated(&reply.nodeid, 1); 1326 /* 1327 TRACE("BMediaRoster::RegisterNode: registered node name '%s', id %ld, addon %ld, flavor %ld\n", node->Name(), node->ID(), addon_id, addon_flavor_id); 1328 TRACE("BMediaRoster::RegisterNode: node this %p\n", node); 1329 TRACE("BMediaRoster::RegisterNode: node fConsumerThis %p\n", node->fConsumerThis); 1330 TRACE("BMediaRoster::RegisterNode: node fProducerThis %p\n", node->fProducerThis); 1331 TRACE("BMediaRoster::RegisterNode: node fFileInterfaceThis %p\n", node->fFileInterfaceThis); 1332 TRACE("BMediaRoster::RegisterNode: node fControllableThis %p\n", node->fControllableThis); 1333 TRACE("BMediaRoster::RegisterNode: node fTimeSourceThis %p\n", node->fTimeSourceThis); 1334 */ 1335 1336 return B_OK; 1337 } 1338 1339 1340 status_t 1341 BMediaRoster::UnregisterNode(BMediaNode * node) 1342 { 1343 CALLED(); 1344 if (node == NULL) 1345 return B_BAD_VALUE; 1346 1347 if (node->fRefCount != 0) { 1348 TRACE("BMediaRoster::UnregisterNode: Warning node name '%s' has local reference count of %ld\n", node->Name(), node->fRefCount); 1349 // no return here, we continue and unregister! 1350 } 1351 if (node->ID() == -2) { 1352 TRACE("BMediaRoster::UnregisterNode: Warning node name '%s' already unregistered\n", node->Name()); 1353 return B_OK; 1354 } 1355 1356 server_unregister_node_request request; 1357 server_unregister_node_reply reply; 1358 status_t rv; 1359 1360 request.nodeid = node->ID(); 1361 request.team = team; 1362 1363 // send a notification 1364 BPrivate::media::notifications::NodesDeleted(&request.nodeid, 1); 1365 1366 rv = QueryServer(SERVER_UNREGISTER_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1367 if (rv != B_OK) { 1368 TRACE("BMediaRoster::UnregisterNode: failed to unregister node name '%s' (error %#lx)\n", node->Name(), rv); 1369 return rv; 1370 } 1371 1372 if (reply.addon_id != -1) 1373 _DormantNodeManager->PutAddon(reply.addon_id); 1374 1375 // we are a friend class of BMediaNode and invalidate this member variable 1376 node->fNodeID = -2; 1377 1378 return B_OK; 1379 } 1380 1381 1382 // thread safe for multiple calls to Roster() 1383 /* static */ BMediaRoster * 1384 BMediaRoster::Roster(status_t* out_error) 1385 { 1386 static BLocker locker("BMediaRoster::Roster locker"); 1387 locker.Lock(); 1388 if (_sDefault == NULL) { 1389 _sDefault = new BMediaRoster(); 1390 if (out_error != NULL) 1391 *out_error = B_OK; 1392 } else { 1393 if (out_error != NULL) 1394 *out_error = B_OK; 1395 } 1396 locker.Unlock(); 1397 return _sDefault; 1398 } 1399 1400 1401 // won't create it if there isn't one 1402 // not thread safe if you call Roster() at the same time 1403 /* static */ BMediaRoster * 1404 BMediaRoster::CurrentRoster() 1405 { 1406 return _sDefault; 1407 } 1408 1409 1410 status_t 1411 BMediaRoster::SetTimeSourceFor(media_node_id node, 1412 media_node_id time_source) 1413 { 1414 UNIMPLEMENTED(); 1415 return B_ERROR; 1416 } 1417 1418 1419 status_t 1420 BMediaRoster::GetParameterWebFor(const media_node & node, 1421 BParameterWeb ** out_web) 1422 { 1423 UNIMPLEMENTED(); 1424 return B_ERROR; 1425 } 1426 1427 1428 status_t 1429 BMediaRoster::StartControlPanel(const media_node & node, 1430 BMessenger * out_messenger) 1431 { 1432 UNIMPLEMENTED(); 1433 return B_ERROR; 1434 } 1435 1436 1437 status_t 1438 BMediaRoster::GetDormantNodes(dormant_node_info * out_info, 1439 int32 * io_count, 1440 const media_format * has_input /* = NULL */, 1441 const media_format * has_output /* = NULL */, 1442 const char * name /* = NULL */, 1443 uint64 require_kinds /* = NULL */, 1444 uint64 deny_kinds /* = NULL */) 1445 { 1446 CALLED(); 1447 if (out_info == NULL) 1448 return B_BAD_VALUE; 1449 if (io_count == NULL) 1450 return B_BAD_VALUE; 1451 if (*io_count <= 0) 1452 return B_BAD_VALUE; 1453 1454 xfer_server_get_dormant_nodes msg; 1455 port_id port; 1456 status_t rv; 1457 1458 port = find_port("media_server port"); 1459 if (port <= B_OK) 1460 return B_ERROR; 1461 1462 msg.maxcount = *io_count; 1463 msg.has_input = (bool) has_input; 1464 if (has_input) 1465 msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format 1466 msg.has_output = (bool) has_output; 1467 if (has_output) 1468 msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format 1469 msg.has_name = (bool) name; 1470 if (name) { 1471 int len = strlen(name); 1472 len = min_c(len, (int)sizeof(msg.name) - 1); 1473 memcpy(msg.name, name, len); 1474 msg.name[len] = 0; 1475 } 1476 msg.require_kinds = require_kinds; 1477 msg.deny_kinds = deny_kinds; 1478 msg.reply_port = _PortPool->GetPort(); 1479 1480 rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg)); 1481 if (rv != B_OK) { 1482 _PortPool->PutPort(msg.reply_port); 1483 return rv; 1484 } 1485 1486 xfer_server_get_dormant_nodes_reply reply; 1487 int32 code; 1488 1489 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 1490 if (rv < B_OK) { 1491 _PortPool->PutPort(msg.reply_port); 1492 return rv; 1493 } 1494 1495 *io_count = reply.count; 1496 1497 if (*io_count > 0) { 1498 rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info)); 1499 if (rv < B_OK) 1500 reply.result = rv; 1501 } 1502 _PortPool->PutPort(msg.reply_port); 1503 1504 return reply.result; 1505 } 1506 1507 1508 status_t 1509 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, 1510 media_node * out_node, 1511 uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ ) 1512 { 1513 CALLED(); 1514 if ((flags & (B_FLAVOR_IS_GLOBAL | B_FLAVOR_IS_LOCAL)) == 0) { 1515 printf("Error: BMediaRoster::InstantiateDormantNode called without flags\n"); 1516 return B_BAD_VALUE; 1517 } 1518 if (out_node == 0) 1519 return B_BAD_VALUE; 1520 1521 // XXX we should not trust the values passed in by the user, 1522 // XXX and ask the server to determine where to insta 1523 1524 1525 // XXX SOMETHING IS VERY WRONG HERE 1526 // if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) == 0 && (flags & B_FLAVOR_IS_LOCAL)) { 1527 if (flags & B_FLAVOR_IS_LOCAL) { 1528 return InstantiateDormantNode(in_info,out_node); 1529 } 1530 1531 // XXX SOMETHING IS VERY WRONG HERE 1532 // if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) { 1533 if (flags & B_FLAVOR_IS_GLOBAL) { 1534 // forward this request into the media_addon_server, 1535 // which in turn will call InstantiateDormantNode() 1536 // to create it there localy 1537 addonserver_instantiate_dormant_node_request request; 1538 addonserver_instantiate_dormant_node_reply reply; 1539 status_t rv; 1540 1541 request.info = in_info; 1542 rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1543 if (rv == B_OK) { 1544 *out_node = reply.node; 1545 } 1546 return rv; 1547 } 1548 1549 // XXX SOMETHING IS VERY WRONG HERE 1550 printf("Error: BMediaRoster::InstantiateDormantNode addon_id %d, flavor_id %d, flags %#08lx\n", (int)in_info.addon, (int)in_info.flavor_id, flags); 1551 1552 return B_ERROR; 1553 } 1554 1555 1556 status_t 1557 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, 1558 media_node * out_node) 1559 { 1560 CALLED(); 1561 1562 // to instantiate a dormant node in the current address space, we need to 1563 // either load the add-on from file and create a new BMediaAddOn class, or 1564 // reuse the cached BMediaAddOn from a previous call 1565 // call BMediaAddOn::InstantiateNodeFor() 1566 // and cache the BMediaAddOn after that for later reuse. 1567 // BeOS R5 does not seem to delete it when the application quits 1568 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that 1569 // resides in the media_addon_server 1570 1571 // RegisterNode() is called automatically for nodes instantiated from add-ons 1572 1573 //XXX TEST! 1574 BMediaAddOn *addon; 1575 BMediaNode *node; 1576 BMessage config; 1577 status_t out_error; 1578 status_t rv; 1579 addon = _DormantNodeManager->GetAddon(in_info.addon); 1580 if (!addon) { 1581 printf("BMediaRoster::InstantiateDormantNode: GetAddon failed\n"); 1582 return B_ERROR; 1583 } 1584 flavor_info temp; // XXX fix this! 1585 temp.name = "XXX flavor_info name"; 1586 temp.info = "XXX flavor_info info"; 1587 temp.internal_id = in_info.flavor_id; 1588 node = addon->InstantiateNodeFor(&temp, &config, &out_error); 1589 if (!node) { 1590 printf("BMediaRoster::InstantiateDormantNode: InstantiateNodeFor failed\n"); 1591 _DormantNodeManager->PutAddon(in_info.addon); 1592 return B_ERROR; 1593 } 1594 rv = RegisterNode(node); 1595 if (rv != B_OK) { 1596 printf("BMediaRoster::InstantiateDormantNode: RegisterNode failed\n"); 1597 delete node; 1598 _DormantNodeManager->PutAddon(in_info.addon); 1599 return B_ERROR; 1600 } 1601 1602 // XXX we must remember in_info.addon and call 1603 // XXX _DormantNodeManager->PutAddon when the 1604 // XXX node is unregistered 1605 // should be handled by RegisterNode() and UnegisterNode() now 1606 1607 *out_node = node->Node(); 1608 return B_OK; 1609 } 1610 1611 1612 status_t 1613 BMediaRoster::GetDormantNodeFor(const media_node & node, 1614 dormant_node_info * out_info) 1615 { 1616 CALLED(); 1617 if (out_info == NULL) 1618 return B_BAD_VALUE; 1619 if (node.node <= 0) 1620 return B_MEDIA_BAD_NODE; 1621 1622 server_get_dormant_node_for_request request; 1623 server_get_dormant_node_for_reply reply; 1624 status_t rv; 1625 1626 request.node = node; 1627 1628 rv = QueryServer(SERVER_GET_DORMANT_NODE_FOR, &request, sizeof(request), &reply, sizeof(reply)); 1629 if (rv != B_OK) 1630 return rv; 1631 1632 *out_info = reply.node_info; 1633 return B_OK; 1634 } 1635 1636 1637 status_t 1638 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant, 1639 dormant_flavor_info * out_flavor) 1640 { 1641 CALLED(); 1642 1643 xfer_server_get_dormant_flavor_info msg; 1644 xfer_server_get_dormant_flavor_info_reply *reply; 1645 port_id port; 1646 status_t rv; 1647 int32 code; 1648 1649 port = find_port("media_server port"); 1650 if (port <= B_OK) 1651 return B_ERROR; 1652 1653 reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000); 1654 if (reply == 0) 1655 return B_ERROR; 1656 1657 msg.addon = in_dormant.addon; 1658 msg.flavor_id = in_dormant.flavor_id; 1659 msg.reply_port = _PortPool->GetPort(); 1660 rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg)); 1661 if (rv != B_OK) { 1662 free(reply); 1663 _PortPool->PutPort(msg.reply_port); 1664 return rv; 1665 } 1666 rv = read_port(msg.reply_port, &code, reply, 16000); 1667 _PortPool->PutPort(msg.reply_port); 1668 1669 if (rv < B_OK) { 1670 free(reply); 1671 return rv; 1672 } 1673 1674 if (reply->result == B_OK) 1675 rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size); 1676 else 1677 rv = reply->result; 1678 1679 free(reply); 1680 return rv; 1681 } 1682 1683 1684 status_t 1685 BMediaRoster::GetLatencyFor(const media_node & producer, 1686 bigtime_t * out_latency) 1687 { 1688 UNIMPLEMENTED(); 1689 *out_latency = 0; 1690 return B_ERROR; 1691 } 1692 1693 1694 status_t 1695 BMediaRoster::GetInitialLatencyFor(const media_node & producer, 1696 bigtime_t * out_latency, 1697 uint32 * out_flags) 1698 { 1699 UNIMPLEMENTED(); 1700 *out_latency = 0; 1701 *out_flags = 0; 1702 return B_ERROR; 1703 } 1704 1705 1706 status_t 1707 BMediaRoster::GetStartLatencyFor(const media_node & time_source, 1708 bigtime_t * out_latency) 1709 { 1710 UNIMPLEMENTED(); 1711 *out_latency = 0; 1712 return B_ERROR; 1713 } 1714 1715 1716 status_t 1717 BMediaRoster::GetFileFormatsFor(const media_node & file_interface, 1718 media_file_format * out_formats, 1719 int32 * io_num_infos) 1720 { 1721 UNIMPLEMENTED(); 1722 return B_ERROR; 1723 } 1724 1725 1726 status_t 1727 BMediaRoster::SetRefFor(const media_node & file_interface, 1728 const entry_ref & file, 1729 bool create_and_truncate, 1730 bigtime_t * out_length) /* if create is false */ 1731 { 1732 UNIMPLEMENTED(); 1733 return B_ERROR; 1734 } 1735 1736 1737 status_t 1738 BMediaRoster::GetRefFor(const media_node & node, 1739 entry_ref * out_file, 1740 BMimeType * mime_type) 1741 { 1742 UNIMPLEMENTED(); 1743 return B_ERROR; 1744 } 1745 1746 1747 status_t 1748 BMediaRoster::SniffRefFor(const media_node & file_interface, 1749 const entry_ref & file, 1750 BMimeType * mime_type, 1751 float * out_capability) 1752 { 1753 UNIMPLEMENTED(); 1754 return B_ERROR; 1755 } 1756 1757 1758 /* This is the generic "here's a file, now can someone please play it" interface */ 1759 status_t 1760 BMediaRoster::SniffRef(const entry_ref & file, 1761 uint64 require_node_kinds, /* if you need an EntityInterface or BufferConsumer or something */ 1762 dormant_node_info * out_node, 1763 BMimeType * mime_type) 1764 { 1765 UNIMPLEMENTED(); 1766 return B_ERROR; 1767 } 1768 1769 1770 status_t 1771 BMediaRoster::GetDormantNodeForType(const BMimeType & type, 1772 uint64 require_node_kinds, 1773 dormant_node_info * out_node) 1774 { 1775 UNIMPLEMENTED(); 1776 return B_ERROR; 1777 } 1778 1779 1780 status_t 1781 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node, 1782 media_file_format * out_read_formats, 1783 int32 in_read_count, 1784 int32 * out_read_count) 1785 { 1786 UNIMPLEMENTED(); 1787 return B_ERROR; 1788 } 1789 1790 1791 status_t 1792 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node, 1793 media_file_format * out_write_formats, 1794 int32 in_write_count, 1795 int32 * out_write_count) 1796 { 1797 UNIMPLEMENTED(); 1798 return B_ERROR; 1799 } 1800 1801 1802 status_t 1803 BMediaRoster::GetFormatFor(const media_output & output, 1804 media_format * io_format, 1805 uint32 flags) 1806 { 1807 UNIMPLEMENTED(); 1808 return B_ERROR; 1809 } 1810 1811 1812 status_t 1813 BMediaRoster::GetFormatFor(const media_input & input, 1814 media_format * io_format, 1815 uint32 flags) 1816 { 1817 UNIMPLEMENTED(); 1818 return B_ERROR; 1819 } 1820 1821 1822 status_t 1823 BMediaRoster::GetFormatFor(const media_node & node, 1824 media_format * io_format, 1825 float quality) 1826 { 1827 UNIMPLEMENTED(); 1828 return B_ERROR; 1829 } 1830 1831 1832 ssize_t 1833 BMediaRoster::GetNodeAttributesFor(const media_node & node, 1834 media_node_attribute * outArray, 1835 size_t inMaxCount) 1836 { 1837 UNIMPLEMENTED(); 1838 return B_ERROR; 1839 } 1840 1841 1842 media_node_id 1843 BMediaRoster::NodeIDFor(port_id source_or_destination_port) 1844 { 1845 CALLED(); 1846 1847 server_node_id_for_request request; 1848 server_node_id_for_reply reply; 1849 status_t rv; 1850 1851 request.port = source_or_destination_port; 1852 1853 rv = QueryServer(SERVER_NODE_ID_FOR, &request, sizeof(request), &reply, sizeof(reply)); 1854 if (rv != B_OK) { 1855 TRACE("BMediaRoster::NodeIDFor: failed (error %#lx)\n", rv); 1856 return -1; 1857 } 1858 1859 return reply.nodeid; 1860 } 1861 1862 1863 status_t 1864 BMediaRoster::GetInstancesFor(media_addon_id addon, 1865 int32 flavor, 1866 media_node_id * out_id, 1867 int32 * io_count) 1868 { 1869 CALLED(); 1870 if (out_id == NULL || io_count == NULL) 1871 return B_BAD_VALUE; 1872 if (*io_count <= 0) 1873 return B_BAD_VALUE; 1874 1875 server_get_instances_for_request request; 1876 server_get_instances_for_reply reply; 1877 status_t rv; 1878 1879 request.maxcount = *io_count; 1880 request.addon_id = addon; 1881 request.addon_flavor_id = flavor; 1882 1883 rv = QueryServer(SERVER_GET_INSTANCES_FOR, &request, sizeof(request), &reply, sizeof(reply)); 1884 if (rv != B_OK) { 1885 TRACE("BMediaRoster::GetLiveNodes failed\n"); 1886 return rv; 1887 } 1888 1889 *io_count = reply.count; 1890 if (reply.count > 0) 1891 memcpy(out_id, reply.node_id, sizeof(media_node_id) * reply.count); 1892 1893 return B_OK; 1894 } 1895 1896 1897 status_t 1898 BMediaRoster::SetRealtimeFlags(uint32 in_enabled) 1899 { 1900 UNIMPLEMENTED(); 1901 return B_ERROR; 1902 } 1903 1904 1905 status_t 1906 BMediaRoster::GetRealtimeFlags(uint32 * out_enabled) 1907 { 1908 UNIMPLEMENTED(); 1909 return B_ERROR; 1910 } 1911 1912 1913 ssize_t 1914 BMediaRoster::AudioBufferSizeFor(int32 channel_count, 1915 uint32 sample_format, 1916 float frame_rate, 1917 bus_type bus_kind) 1918 { 1919 UNIMPLEMENTED(); 1920 return 4096; 1921 } 1922 1923 1924 /* Use MediaFlags to inquire about specific features of the Media Kit. */ 1925 /* Returns < 0 for "not present", positive size for output data size. */ 1926 /* 0 means that the capability is present, but no data about it. */ 1927 /* static */ ssize_t 1928 BMediaRoster::MediaFlags(media_flags cap, 1929 void * buf, 1930 size_t maxSize) 1931 { 1932 UNIMPLEMENTED(); 1933 return 0; 1934 } 1935 1936 1937 1938 /* BLooper overrides */ 1939 /* virtual */ void 1940 BMediaRoster::MessageReceived(BMessage * message) 1941 { 1942 UNIMPLEMENTED(); 1943 } 1944 1945 /* virtual */ bool 1946 BMediaRoster::QuitRequested() 1947 { 1948 UNIMPLEMENTED(); 1949 return true; 1950 } 1951 1952 /* virtual */ BHandler * 1953 BMediaRoster::ResolveSpecifier(BMessage *msg, 1954 int32 index, 1955 BMessage *specifier, 1956 int32 form, 1957 const char *property) 1958 { 1959 UNIMPLEMENTED(); 1960 return 0; 1961 } 1962 1963 1964 /* virtual */ status_t 1965 BMediaRoster::GetSupportedSuites(BMessage *data) 1966 { 1967 UNIMPLEMENTED(); 1968 return B_ERROR; 1969 } 1970 1971 1972 BMediaRoster::~BMediaRoster() 1973 { 1974 CALLED(); 1975 BMessage msg(MEDIA_SERVER_UNREGISTER_APP); 1976 BMessage reply; 1977 msg.AddInt32("team",team); 1978 QueryServer(&msg, &reply); 1979 } 1980 1981 1982 /************************************************************* 1983 * private BMediaRoster 1984 *************************************************************/ 1985 1986 // deprecated call 1987 status_t 1988 BMediaRoster::SetOutputBuffersFor(const media_source & output, 1989 BBufferGroup * group, 1990 bool will_reclaim ) 1991 { 1992 UNIMPLEMENTED(); 1993 debugger("BMediaRoster::SetOutputBuffersFor missing\n"); 1994 return B_ERROR; 1995 } 1996 1997 1998 /* FBC stuffing (Mmmh, Stuffing!) */ 1999 status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; } 2000 status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; } 2001 status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; } 2002 status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; } 2003 status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; } 2004 status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; } 2005 status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; } 2006 status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; } 2007 2008 2009 BMediaRoster::BMediaRoster() : 2010 BLooper("BMediaRoster looper",B_NORMAL_PRIORITY,B_LOOPER_PORT_DEFAULT_CAPACITY) 2011 { 2012 CALLED(); 2013 BMessage msg(MEDIA_SERVER_REGISTER_APP); 2014 BMessage reply; 2015 msg.AddInt32("team",team); 2016 QueryServer(&msg,&reply); 2017 } 2018 2019 /* static */ status_t 2020 BMediaRoster::ParseCommand(BMessage & reply) 2021 { 2022 UNIMPLEMENTED(); 2023 return B_ERROR; 2024 } 2025 2026 2027 2028 status_t 2029 BMediaRoster::GetDefaultInfo(media_node_id for_default, 2030 BMessage & out_config) 2031 { 2032 UNIMPLEMENTED(); 2033 return B_ERROR; 2034 } 2035 2036 2037 2038 status_t 2039 BMediaRoster::SetRunningDefault(media_node_id for_default, 2040 const media_node & node) 2041 { 2042 UNIMPLEMENTED(); 2043 return B_ERROR; 2044 } 2045 2046 2047 /************************************************************* 2048 * static BMediaRoster variables 2049 *************************************************************/ 2050 2051 bool BMediaRoster::_isMediaServer; 2052 port_id BMediaRoster::_mReplyPort; 2053 int32 BMediaRoster::_mReplyPortRes; 2054 int32 BMediaRoster::_mReplyPortUnavailCount; 2055 BMediaRoster * BMediaRoster::_sDefault = NULL; 2056 2057