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