1 /*********************************************************************** 2 * AUTHOR: Marcus Overhagen 3 * FILE: MediaRoster.cpp 4 * DESCR: 5 ***********************************************************************/ 6 #include <MediaRoster.h> 7 #include <Locker.h> 8 #include <Message.h> 9 #include <Messenger.h> 10 #include <StopWatch.h> 11 #include <OS.h> 12 #include <String.h> 13 #include <TimeSource.h> 14 #undef DEBUG 15 #define DEBUG 3 16 #include "debug.h" 17 #include "PortPool.h" 18 #include "ServerInterface.h" 19 #include "DataExchange.h" 20 #include "DormantNodeManager.h" 21 #include "Notifications.h" 22 23 using namespace BPrivate::media; 24 25 namespace BPrivate { namespace media { 26 extern team_id team; 27 }; }; 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() { delete BMediaRoster::_sDefault; } 36 }; 37 38 _DefaultDeleter _deleter; 39 40 namespace MediaKitPrivate 41 { 42 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 47 status_t GetNode(node_type type, media_node * out_node, int32 * out_input_id, BString * out_input_name) 48 { 49 if (out_node == NULL) 50 return B_BAD_VALUE; 51 52 server_get_node_request request; 53 server_get_node_reply reply; 54 status_t rv; 55 56 request.type = type; 57 rv = QueryServer(SERVER_GET_NODE, &request, sizeof(request), &reply, sizeof(reply)); 58 if (rv != B_OK) 59 return rv; 60 61 *out_node = reply.node; 62 if (out_input_id) 63 *out_input_id = reply.input_id; 64 if (out_input_name) 65 *out_input_name = reply.input_name; 66 return rv; 67 } 68 69 status_t SetNode(node_type type, const media_node *node, const dormant_node_info *info, const media_input *input) 70 { 71 server_set_node_request request; 72 server_set_node_reply reply; 73 74 request.type = type; 75 request.use_node = node ? true : false; 76 if (node) 77 request.node = *node; 78 request.use_dni = info ? true : false; 79 if (info) 80 request.dni = *info; 81 request.use_input = input ? true : false; 82 if (input) 83 request.input = *input; 84 85 return QueryServer(SERVER_SET_NODE, &request, sizeof(request), &reply, sizeof(reply)); 86 } 87 88 }; 89 90 /************************************************************* 91 * public BMediaRoster 92 *************************************************************/ 93 94 status_t 95 BMediaRoster::GetVideoInput(media_node * out_node) 96 { 97 CALLED(); 98 return MediaKitPrivate::GetNode(VIDEO_INPUT, out_node); 99 } 100 101 102 status_t 103 BMediaRoster::GetAudioInput(media_node * out_node) 104 { 105 CALLED(); 106 return MediaKitPrivate::GetNode(AUDIO_INPUT, out_node); 107 } 108 109 110 status_t 111 BMediaRoster::GetVideoOutput(media_node * out_node) 112 { 113 CALLED(); 114 return MediaKitPrivate::GetNode(VIDEO_OUTPUT, out_node); 115 } 116 117 118 status_t 119 BMediaRoster::GetAudioMixer(media_node * out_node) 120 { 121 CALLED(); 122 return MediaKitPrivate::GetNode(AUDIO_MIXER, out_node); 123 } 124 125 126 status_t 127 BMediaRoster::GetAudioOutput(media_node * out_node) 128 { 129 CALLED(); 130 return MediaKitPrivate::GetNode(AUDIO_OUTPUT, out_node); 131 } 132 133 134 status_t 135 BMediaRoster::GetAudioOutput(media_node * out_node, 136 int32 * out_input_id, 137 BString * out_input_name) 138 { 139 CALLED(); 140 return MediaKitPrivate::GetNode(AUDIO_OUTPUT_EX, out_node, out_input_id, out_input_name); 141 } 142 143 144 status_t 145 BMediaRoster::GetTimeSource(media_node * out_node) 146 { 147 CALLED(); 148 return MediaKitPrivate::GetNode(TIME_SOURCE, out_node); 149 } 150 151 152 status_t 153 BMediaRoster::SetVideoInput(const media_node & producer) 154 { 155 CALLED(); 156 return MediaKitPrivate::SetNode(VIDEO_INPUT, &producer); 157 } 158 159 160 status_t 161 BMediaRoster::SetVideoInput(const dormant_node_info & producer) 162 { 163 CALLED(); 164 return MediaKitPrivate::SetNode(VIDEO_INPUT, NULL, &producer); 165 } 166 167 168 status_t 169 BMediaRoster::SetAudioInput(const media_node & producer) 170 { 171 CALLED(); 172 return MediaKitPrivate::SetNode(AUDIO_INPUT, &producer); 173 } 174 175 176 status_t 177 BMediaRoster::SetAudioInput(const dormant_node_info & producer) 178 { 179 CALLED(); 180 return MediaKitPrivate::SetNode(AUDIO_INPUT, NULL, &producer); 181 } 182 183 184 status_t 185 BMediaRoster::SetVideoOutput(const media_node & consumer) 186 { 187 CALLED(); 188 return MediaKitPrivate::SetNode(VIDEO_OUTPUT, &consumer); 189 } 190 191 192 status_t 193 BMediaRoster::SetVideoOutput(const dormant_node_info & consumer) 194 { 195 CALLED(); 196 return MediaKitPrivate::SetNode(VIDEO_OUTPUT, NULL, &consumer); 197 } 198 199 200 status_t 201 BMediaRoster::SetAudioOutput(const media_node & consumer) 202 { 203 CALLED(); 204 return MediaKitPrivate::SetNode(AUDIO_OUTPUT, &consumer); 205 } 206 207 208 status_t 209 BMediaRoster::SetAudioOutput(const media_input & input_to_output) 210 { 211 CALLED(); 212 return MediaKitPrivate::SetNode(AUDIO_OUTPUT, NULL, NULL, &input_to_output); 213 } 214 215 216 status_t 217 BMediaRoster::SetAudioOutput(const dormant_node_info & consumer) 218 { 219 CALLED(); 220 return MediaKitPrivate::SetNode(AUDIO_OUTPUT, NULL, &consumer); 221 } 222 223 224 status_t 225 BMediaRoster::GetNodeFor(media_node_id node, 226 media_node * clone) 227 { 228 UNIMPLEMENTED(); 229 return B_ERROR; 230 } 231 232 233 status_t 234 BMediaRoster::GetSystemTimeSource(media_node * clone) 235 { 236 CALLED(); 237 return MediaKitPrivate::GetNode(SYSTEM_TIME_SOURCE, clone); 238 } 239 240 241 status_t 242 BMediaRoster::ReleaseNode(const media_node & node) 243 { 244 UNIMPLEMENTED(); 245 return B_ERROR; 246 } 247 248 249 250 BTimeSource * 251 BMediaRoster::MakeTimeSourceFor(const media_node & for_node) 252 { 253 UNIMPLEMENTED(); 254 return 0; 255 } 256 257 258 status_t 259 BMediaRoster::Connect(const media_source & from, 260 const media_destination & to, 261 media_format * io_format, 262 media_output * out_output, 263 media_input * out_input) 264 { 265 return BMediaRoster::Connect(from, to, io_format, out_output, out_input, 0); 266 } 267 268 269 status_t 270 BMediaRoster::Connect(const media_source & from, 271 const media_destination & to, 272 media_format * io_format, 273 media_output * out_output, 274 media_input * out_input, 275 uint32 in_flags, 276 void * _reserved) 277 { 278 CALLED(); 279 if (io_format == NULL || out_output == NULL || out_input == NULL) 280 return B_BAD_VALUE; 281 if (from == media_source::null) 282 return B_MEDIA_BAD_SOURCE; 283 if (to == media_destination::null) 284 return B_MEDIA_BAD_DESTINATION; 285 286 status_t rv; 287 producer_format_proposal_request request1; 288 producer_format_proposal_reply reply1; 289 290 // BBufferProducer::FormatProposal 291 request1.output = from; 292 request1.format = *io_format; 293 rv = QueryPort(from.port, PRODUCER_FORMAT_PROPOSAL, &request1, sizeof(request1), &reply1, sizeof(reply1)); 294 if (rv != B_OK) { 295 TRACE("BMediaRoster::Connect: aborted after BBufferProducer::FormatProposal, status = %#lx\n",rv); 296 return rv; 297 } 298 // reply1.format now contains the format proposed by the producer 299 300 consumer_accept_format_request request2; 301 consumer_accept_format_reply reply2; 302 303 // BBufferConsumer::AcceptFormat 304 request2.dest = to; 305 request2.format = reply1.format; 306 rv = QueryPort(to.port, CONSUMER_ACCEPT_FORMAT, &request2, sizeof(request2), &reply2, sizeof(reply2)); 307 if (rv != B_OK) { 308 TRACE("BMediaRoster::Connect: aborted after BBufferConsumer::AcceptFormat, status = %#lx\n",rv); 309 return rv; 310 } 311 // reply2.format now contains the format accepted by the consumer 312 313 // BBufferProducer::PrepareToConnect 314 producer_prepare_to_connect_request request3; 315 producer_prepare_to_connect_reply reply3; 316 317 request3.source = from; 318 request3.destination = to; 319 request3.format = reply2.format; 320 strcpy(request3.name, "XXX some default name"); // XXX fix this 321 rv = QueryPort(from.port, PRODUCER_PREPARE_TO_CONNECT, &request3, sizeof(request3), &reply3, sizeof(reply3)); 322 if (rv != B_OK) { 323 TRACE("BMediaRoster::Connect: aborted after BBufferProducer::PrepareToConnect, status = %#lx\n",rv); 324 return rv; 325 } 326 // reply3.format is still our pretty media format 327 // reply3.out_source the real source to be used for the connection 328 // reply3.name the name BBufferConsumer::Connected will see in the outInput->name argument 329 330 // BBufferConsumer::Connected 331 consumer_connected_request request4; 332 consumer_connected_reply reply4; 333 status_t con_status; 334 335 request4.producer = reply3.out_source; 336 request4.where = to; 337 request4.with_format = reply3.format; 338 con_status = QueryPort(to.port, CONSUMER_CONNECTED, &request4, sizeof(request4), &reply4, sizeof(reply4)); 339 if (con_status != B_OK) { 340 TRACE("BMediaRoster::Connect: aborting after BBufferConsumer::Connected, status = %#lx\n",con_status); 341 // we do NOT return here! 342 } 343 // con_status contains the status code to be supplied to BBufferProducer::Connect's status argument 344 // reply4.input contains the media_input that describes the connection from the consumer point of view 345 346 // BBufferProducer::Connect 347 producer_connect_request request5; 348 producer_connect_reply reply5; 349 350 request5.error = con_status; 351 request5.source = reply3.out_source; 352 request5.destination = reply4.input.destination; 353 request5.format = reply3.format; // XXX reply4.input.format ??? 354 strcpy(request5.name, reply4.input.name); 355 rv = QueryPort(reply4.input.node.port, PRODUCER_CONNECT, &request5, sizeof(request5), &reply5, sizeof(reply5)); 356 if (con_status != B_OK) { 357 TRACE("BMediaRoster::Connect: aborted\n"); 358 return con_status; 359 } 360 if (rv != B_OK) { 361 TRACE("BMediaRoster::Connect: aborted after BBufferProducer::Connect, status = %#lx\n",rv); 362 return rv; 363 } 364 // reply5.name contains the name assigned to the connection by the producer 365 366 // find the output node 367 // XXX isn't there a easier way? 368 media_node sourcenode; 369 GetNodeFor(NodeIDFor(from.port), &sourcenode); 370 ReleaseNode(sourcenode); 371 372 // initilize connection info 373 *io_format = reply3.format; 374 *out_input = reply4.input; 375 out_output->node = sourcenode; 376 out_output->source = reply4.input.source; 377 out_output->destination = reply4.input.destination; 378 out_output->format = reply4.input.format; 379 strcpy(out_output->name, reply5.name); 380 381 // the connection is now made 382 383 384 // XXX register connection with server 385 386 387 // XXX if (mute) BBufferProducer::EnableOutput(false) 388 389 390 return B_OK; 391 }; 392 393 394 status_t 395 BMediaRoster::Disconnect(media_node_id source_node, 396 const media_source & source, 397 media_node_id destination_node, 398 const media_destination & destination) 399 { 400 UNIMPLEMENTED(); 401 return B_ERROR; 402 } 403 404 405 status_t 406 BMediaRoster::StartNode(const media_node & node, 407 bigtime_t at_performance_time) 408 { 409 CALLED(); 410 if (node.node == 0) 411 return B_MEDIA_BAD_NODE; 412 413 xfer_node_start msg; 414 msg.performance_time = at_performance_time; 415 416 return write_port(node.port, NODE_START, &msg, sizeof(msg)); 417 } 418 419 420 status_t 421 BMediaRoster::StopNode(const media_node & node, 422 bigtime_t at_performance_time, 423 bool immediate) 424 { 425 CALLED(); 426 if (node.node == 0) 427 return B_MEDIA_BAD_NODE; 428 429 xfer_node_stop msg; 430 msg.performance_time = at_performance_time; 431 msg.immediate = immediate; 432 433 return write_port(node.port, NODE_STOP, &msg, sizeof(msg)); 434 } 435 436 437 status_t 438 BMediaRoster::SeekNode(const media_node & node, 439 bigtime_t to_media_time, 440 bigtime_t at_performance_time) 441 { 442 CALLED(); 443 if (node.node == 0) 444 return B_MEDIA_BAD_NODE; 445 446 xfer_node_seek msg; 447 msg.media_time = to_media_time; 448 msg.performance_time = at_performance_time; 449 450 return write_port(node.port, NODE_SEEK, &msg, sizeof(msg)); 451 } 452 453 454 status_t 455 BMediaRoster::StartTimeSource(const media_node & node, 456 bigtime_t at_real_time) 457 { 458 CALLED(); 459 if (node.node == 0) 460 return B_MEDIA_BAD_NODE; 461 if ((node.kind & B_TIME_SOURCE) == 0) 462 return B_MEDIA_BAD_NODE; 463 464 BTimeSource::time_source_op_info msg; 465 msg.op = BTimeSource::B_TIMESOURCE_START; 466 msg.real_time = at_real_time; 467 468 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 469 } 470 471 472 status_t 473 BMediaRoster::StopTimeSource(const media_node & node, 474 bigtime_t at_real_time, 475 bool immediate) 476 { 477 CALLED(); 478 if (node.node == 0) 479 return B_MEDIA_BAD_NODE; 480 if ((node.kind & B_TIME_SOURCE) == 0) 481 return B_MEDIA_BAD_NODE; 482 483 BTimeSource::time_source_op_info msg; 484 msg.op = immediate ? BTimeSource::B_TIMESOURCE_STOP_IMMEDIATELY : BTimeSource::B_TIMESOURCE_STOP; 485 msg.real_time = at_real_time; 486 487 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 488 } 489 490 491 status_t 492 BMediaRoster::SeekTimeSource(const media_node & node, 493 bigtime_t to_performance_time, 494 bigtime_t at_real_time) 495 { 496 CALLED(); 497 if (node.node == 0) 498 return B_MEDIA_BAD_NODE; 499 if ((node.kind & B_TIME_SOURCE) == 0) 500 return B_MEDIA_BAD_NODE; 501 502 BTimeSource::time_source_op_info msg; 503 msg.op = BTimeSource::B_TIMESOURCE_SEEK; 504 msg.real_time = at_real_time; 505 msg.performance_time = to_performance_time; 506 507 return write_port(node.port, TIMESOURCE_OP, &msg, sizeof(msg)); 508 } 509 510 511 status_t 512 BMediaRoster::SyncToNode(const media_node & node, 513 bigtime_t at_time, 514 bigtime_t timeout) 515 { 516 UNIMPLEMENTED(); 517 return B_ERROR; 518 } 519 520 521 status_t 522 BMediaRoster::SetRunModeNode(const media_node & node, 523 BMediaNode::run_mode mode) 524 { 525 CALLED(); 526 if (node.node == 0) 527 return B_MEDIA_BAD_NODE; 528 529 xfer_node_set_run_mode msg; 530 msg.mode = mode; 531 532 return write_port(node.port, NODE_SET_RUN_MODE, &msg, sizeof(msg)); 533 } 534 535 536 status_t 537 BMediaRoster::PrerollNode(const media_node & node) 538 { 539 CALLED(); 540 if (node.node == 0) 541 return B_MEDIA_BAD_NODE; 542 543 char dummy; 544 return write_port(node.port, NODE_PREROLL, &dummy, sizeof(dummy)); 545 } 546 547 548 status_t 549 BMediaRoster::RollNode(const media_node & node, 550 bigtime_t startPerformance, 551 bigtime_t stopPerformance, 552 bigtime_t atMediaTime) 553 { 554 UNIMPLEMENTED(); 555 return B_ERROR; 556 } 557 558 559 status_t 560 BMediaRoster::SetProducerRunModeDelay(const media_node & node, 561 bigtime_t delay, 562 BMediaNode::run_mode mode) 563 { 564 UNIMPLEMENTED(); 565 return B_ERROR; 566 } 567 568 569 status_t 570 BMediaRoster::SetProducerRate(const media_node & producer, 571 int32 numer, 572 int32 denom) 573 { 574 CALLED(); 575 if (producer.node == 0) 576 return B_MEDIA_BAD_NODE; 577 if ((producer.kind & B_BUFFER_PRODUCER) == 0) 578 return B_MEDIA_BAD_NODE; 579 580 xfer_producer_set_play_rate msg; 581 xfer_producer_set_play_rate_reply reply; 582 status_t rv; 583 int32 code; 584 585 msg.numer = numer; 586 msg.denom = denom; 587 msg.reply_port = _PortPool->GetPort(); 588 rv = write_port(producer.node, PRODUCER_SET_PLAY_RATE, &msg, sizeof(msg)); 589 if (rv != B_OK) { 590 _PortPool->PutPort(msg.reply_port); 591 return rv; 592 } 593 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 594 _PortPool->PutPort(msg.reply_port); 595 return (rv < B_OK) ? rv : reply.result; 596 } 597 598 599 600 /* Nodes will have available inputs/outputs as long as they are capable */ 601 /* of accepting more connections. The node may create an additional */ 602 /* output or input as the currently available is taken into usage. */ 603 status_t 604 BMediaRoster::GetLiveNodeInfo(const media_node & node, 605 live_node_info * out_live_info) 606 { 607 UNIMPLEMENTED(); 608 return B_ERROR; 609 } 610 611 612 status_t 613 BMediaRoster::GetLiveNodes(live_node_info * out_live_nodes, 614 int32 * io_total_count, 615 const media_format * has_input, 616 const media_format * has_output, 617 const char * name, 618 uint64 node_kinds) 619 { 620 UNIMPLEMENTED(); 621 return B_ERROR; 622 } 623 624 625 status_t 626 BMediaRoster::GetFreeInputsFor(const media_node & node, 627 media_input * out_free_inputs, 628 int32 buf_num_inputs, 629 int32 * out_total_count, 630 media_type filter_type) 631 { 632 UNIMPLEMENTED(); 633 return B_ERROR; 634 } 635 636 637 status_t 638 BMediaRoster::GetConnectedInputsFor(const media_node & node, 639 media_input * out_active_inputs, 640 int32 buf_num_inputs, 641 int32 * out_total_count) 642 { 643 UNIMPLEMENTED(); 644 return B_ERROR; 645 } 646 647 648 status_t 649 BMediaRoster::GetAllInputsFor(const media_node & node, 650 media_input * out_inputs, 651 int32 buf_num_inputs, 652 int32 * out_total_count) 653 { 654 CALLED(); 655 if (node.node == 0 || (node.kind & B_BUFFER_CONSUMER) == 0) 656 return B_MEDIA_BAD_NODE; 657 if (out_inputs == NULL || out_total_count == NULL) 658 return B_BAD_VALUE; 659 660 status_t rv; 661 status_t rv2; 662 port_id port; 663 int32 code; 664 int32 cookie; 665 666 port = _PortPool->GetPort(); 667 *out_total_count = 0; 668 cookie = 0; 669 rv = B_OK; 670 for (int32 i = 0; i < buf_num_inputs; i++) { 671 xfer_consumer_get_next_input msg; 672 xfer_consumer_get_next_input_reply reply; 673 msg.cookie = cookie; 674 msg.reply_port = port; 675 rv = write_port(node.port, CONSUMER_GET_NEXT_INPUT, &msg, sizeof(msg)); 676 if (rv != B_OK) 677 break; 678 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 679 if (rv < B_OK || reply.result != B_OK) 680 break; 681 *out_total_count += 1; 682 out_inputs[i] = reply.input; 683 cookie = reply.cookie; 684 } 685 _PortPool->PutPort(port); 686 687 xfer_consumer_dispose_input_cookie msg2; 688 msg2.cookie = cookie; 689 rv2 = write_port(node.port, CONSUMER_DISPOSE_INPUT_COOKIE, &msg2, sizeof(msg2)); 690 691 return (rv < B_OK) ? rv : rv2; 692 } 693 694 695 status_t 696 BMediaRoster::GetFreeOutputsFor(const media_node & node, 697 media_output * out_free_outputs, 698 int32 buf_num_outputs, 699 int32 * out_total_count, 700 media_type filter_type) 701 { 702 UNIMPLEMENTED(); 703 return B_ERROR; 704 } 705 706 707 status_t 708 BMediaRoster::GetConnectedOutputsFor(const media_node & node, 709 media_output * out_active_outputs, 710 int32 buf_num_outputs, 711 int32 * out_total_count) 712 { 713 UNIMPLEMENTED(); 714 return B_ERROR; 715 } 716 717 718 status_t 719 BMediaRoster::GetAllOutputsFor(const media_node & node, 720 media_output * out_outputs, 721 int32 buf_num_outputs, 722 int32 * out_total_count) 723 { 724 CALLED(); 725 if (node.node == 0 || (node.kind & B_BUFFER_PRODUCER) == 0) 726 return B_MEDIA_BAD_NODE; 727 if (out_outputs == NULL || out_total_count == NULL) 728 return B_BAD_VALUE; 729 730 status_t rv; 731 status_t rv2; 732 port_id port; 733 int32 code; 734 int32 cookie; 735 736 port = _PortPool->GetPort(); 737 *out_total_count = 0; 738 cookie = 0; 739 rv = B_OK; 740 for (int32 i = 0; i < buf_num_outputs; i++) { 741 xfer_producer_get_next_output msg; 742 xfer_producer_get_next_output_reply reply; 743 msg.cookie = cookie; 744 msg.reply_port = port; 745 rv = write_port(node.port, PRODUCER_GET_NEXT_OUTPUT, &msg, sizeof(msg)); 746 if (rv != B_OK) 747 break; 748 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 749 if (rv < B_OK || reply.result != B_OK) 750 break; 751 *out_total_count += 1; 752 out_outputs[i] = reply.output; 753 cookie = reply.cookie; 754 } 755 _PortPool->PutPort(port); 756 757 xfer_producer_dispose_output_cookie msg2; 758 msg2.cookie = cookie; 759 rv2 = write_port(node.port, PRODUCER_DISPOSE_OUTPUT_COOKIE, &msg2, sizeof(msg2)); 760 761 return (rv < B_OK) ? rv : rv2; 762 } 763 764 765 status_t 766 BMediaRoster::StartWatching(const BMessenger & where) 767 { 768 CALLED(); 769 if (!where.IsValid()) { 770 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 771 return B_BAD_VALUE; 772 } 773 return BPrivate::media::notifications::Register(where, media_node::null, B_MEDIA_WILDCARD); 774 } 775 776 777 status_t 778 BMediaRoster::StartWatching(const BMessenger & where, 779 int32 notificationType) 780 { 781 CALLED(); 782 if (!where.IsValid()) { 783 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 784 return B_BAD_VALUE; 785 } 786 if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) { 787 TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); 788 return B_BAD_VALUE; 789 } 790 return BPrivate::media::notifications::Register(where, media_node::null, notificationType); 791 } 792 793 794 status_t 795 BMediaRoster::StartWatching(const BMessenger & where, 796 const media_node & node, 797 int32 notificationType) 798 { 799 CALLED(); 800 if (!where.IsValid()) { 801 TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); 802 return B_BAD_VALUE; 803 } 804 if (node.node == 0) { 805 TRACE("BMediaRoster::StartWatching: node invalid!\n"); 806 return B_MEDIA_BAD_NODE; 807 } 808 if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) { 809 TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); 810 return B_BAD_VALUE; 811 } 812 return BPrivate::media::notifications::Register(where, node, notificationType); 813 } 814 815 816 status_t 817 BMediaRoster::StopWatching(const BMessenger & where) 818 { 819 CALLED(); 820 // messenger may already be invalid, so we don't check this 821 return BPrivate::media::notifications::Unregister(where, media_node::null, B_MEDIA_WILDCARD); 822 } 823 824 825 status_t 826 BMediaRoster::StopWatching(const BMessenger & where, 827 int32 notificationType) 828 { 829 CALLED(); 830 // messenger may already be invalid, so we don't check this 831 if (false == BPrivate::media::notifications::IsValidNotificationRequest(false, notificationType)) { 832 TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); 833 return B_BAD_VALUE; 834 } 835 return BPrivate::media::notifications::Unregister(where, media_node::null, notificationType); 836 } 837 838 839 status_t 840 BMediaRoster::StopWatching(const BMessenger & where, 841 const media_node & node, 842 int32 notificationType) 843 { 844 CALLED(); 845 // messenger may already be invalid, so we don't check this 846 if (node.node == 0) { 847 TRACE("BMediaRoster::StopWatching: node invalid!\n"); 848 return B_MEDIA_BAD_NODE; 849 } 850 if (false == BPrivate::media::notifications::IsValidNotificationRequest(true, notificationType)) { 851 TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); 852 return B_BAD_VALUE; 853 } 854 return BPrivate::media::notifications::Unregister(where, node, notificationType); 855 } 856 857 858 status_t 859 BMediaRoster::RegisterNode(BMediaNode * node) 860 { 861 CALLED(); 862 if (node == NULL) 863 return B_BAD_VALUE; 864 865 xfer_node_registered msg; 866 msg.node_id = 1; 867 868 return node->HandleMessage(NODE_REGISTERED,&msg,sizeof(msg)); 869 } 870 871 872 status_t 873 BMediaRoster::UnregisterNode(BMediaNode * node) 874 { 875 UNIMPLEMENTED(); 876 return B_ERROR; 877 } 878 879 880 // thread safe for multiple calls to Roster() 881 /* static */ BMediaRoster * 882 BMediaRoster::Roster(status_t* out_error) 883 { 884 CALLED(); 885 static BLocker locker("BMediaRoster::Roster locker"); 886 locker.Lock(); 887 if (_sDefault == NULL) { 888 _sDefault = new BMediaRoster(); 889 if (out_error != NULL) 890 *out_error = B_OK; 891 } else { 892 if (out_error != NULL) 893 *out_error = B_OK; 894 } 895 locker.Unlock(); 896 return _sDefault; 897 } 898 899 900 // won't create it if there isn't one 901 // not thread safe if you call Roster() at the same time 902 /* static */ BMediaRoster * 903 BMediaRoster::CurrentRoster() 904 { 905 CALLED(); 906 return _sDefault; 907 } 908 909 910 status_t 911 BMediaRoster::SetTimeSourceFor(media_node_id node, 912 media_node_id time_source) 913 { 914 UNIMPLEMENTED(); 915 return B_ERROR; 916 } 917 918 919 status_t 920 BMediaRoster::GetParameterWebFor(const media_node & node, 921 BParameterWeb ** out_web) 922 { 923 UNIMPLEMENTED(); 924 return B_ERROR; 925 } 926 927 928 status_t 929 BMediaRoster::StartControlPanel(const media_node & node, 930 BMessenger * out_messenger) 931 { 932 UNIMPLEMENTED(); 933 return B_ERROR; 934 } 935 936 937 status_t 938 BMediaRoster::GetDormantNodes(dormant_node_info * out_info, 939 int32 * io_count, 940 const media_format * has_input /* = NULL */, 941 const media_format * has_output /* = NULL */, 942 const char * name /* = NULL */, 943 uint64 require_kinds /* = NULL */, 944 uint64 deny_kinds /* = NULL */) 945 { 946 CALLED(); 947 if (out_info == NULL) 948 return B_BAD_VALUE; 949 if (io_count == NULL) 950 return B_BAD_VALUE; 951 if (*io_count <= 0) 952 return B_BAD_VALUE; 953 954 xfer_server_get_dormant_nodes msg; 955 port_id port; 956 status_t rv; 957 958 port = find_port("media_server port"); 959 if (port <= B_OK) 960 return B_ERROR; 961 962 msg.maxcount = *io_count; 963 msg.has_input = (bool) has_input; 964 if (has_input) 965 msg.inputformat = *has_input; // XXX we should not make a flat copy of media_format 966 msg.has_output = (bool) has_output; 967 if (has_output) 968 msg.outputformat = *has_output;; // XXX we should not make a flat copy of media_format 969 msg.has_name = (bool) name; 970 if (name) { 971 int len = min_c(strlen(name),sizeof(msg.name) - 1); 972 memcpy(msg.name,name,len); 973 msg.name[len] = 0; 974 } 975 msg.require_kinds = require_kinds; 976 msg.deny_kinds = deny_kinds; 977 msg.reply_port = _PortPool->GetPort(); 978 979 rv = write_port(port, SERVER_GET_DORMANT_NODES, &msg, sizeof(msg)); 980 if (rv != B_OK) { 981 _PortPool->PutPort(msg.reply_port); 982 return rv; 983 } 984 985 xfer_server_get_dormant_nodes_reply reply; 986 int32 code; 987 988 rv = read_port(msg.reply_port, &code, &reply, sizeof(reply)); 989 if (rv < B_OK) { 990 _PortPool->PutPort(msg.reply_port); 991 return rv; 992 } 993 994 *io_count = reply.count; 995 996 if (*io_count > 0) { 997 rv = read_port(msg.reply_port, &code, out_info, *io_count * sizeof(dormant_node_info)); 998 if (rv < B_OK) 999 reply.result = rv; 1000 } 1001 _PortPool->PutPort(msg.reply_port); 1002 1003 return reply.result; 1004 } 1005 1006 1007 status_t 1008 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, 1009 media_node * out_node, 1010 uint32 flags /* currently B_FLAVOR_IS_GLOBAL or B_FLAVOR_IS_LOCAL */ ) 1011 { 1012 CALLED(); 1013 if ((flags & (B_FLAVOR_IS_GLOBAL | B_FLAVOR_IS_LOCAL)) == 0) { 1014 printf("Error: BMediaRoster::InstantiateDormantNode called without flags\n"); 1015 return B_BAD_VALUE; 1016 } 1017 if (out_node == 0) 1018 return B_BAD_VALUE; 1019 1020 // XXX we should not trust the values passed in by the user, 1021 // XXX and ask the server to determine where to insta 1022 1023 1024 // XXX SOMETHING IS VERY WRONG HERE 1025 // if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) == 0 && (flags & B_FLAVOR_IS_LOCAL)) { 1026 if (flags & B_FLAVOR_IS_LOCAL) { 1027 return InstantiateDormantNode(in_info,out_node); 1028 } 1029 1030 // XXX SOMETHING IS VERY WRONG HERE 1031 // if ((in_info.flavor_flags & B_FLAVOR_IS_GLOBAL) || (flags & B_FLAVOR_IS_GLOBAL)) { 1032 if (flags & B_FLAVOR_IS_GLOBAL) { 1033 // forward this request into the media_addon_server, 1034 // which in turn will call InstantiateDormantNode() 1035 // to create it there localy 1036 addonserver_instantiate_dormant_node_request request; 1037 addonserver_instantiate_dormant_node_reply reply; 1038 status_t rv; 1039 1040 request.info = in_info; 1041 rv = QueryAddonServer(ADDONSERVER_INSTANTIATE_DORMANT_NODE, &request, sizeof(request), &reply, sizeof(reply)); 1042 if (rv == B_OK) { 1043 *out_node = reply.node; 1044 } 1045 return rv; 1046 } 1047 1048 // XXX SOMETHING IS VERY WRONG HERE 1049 printf("Error: BMediaRoster::InstantiateDormantNode addon_id %d, flavor_id %d, flags %#08lx\n", (int)in_info.addon, (int)in_info.flavor_id, flags); 1050 1051 return B_ERROR; 1052 } 1053 1054 1055 status_t 1056 BMediaRoster::InstantiateDormantNode(const dormant_node_info & in_info, 1057 media_node * out_node) 1058 { 1059 CALLED(); 1060 1061 // to instantiate a dormant node in the current address space, we need to 1062 // either load the add-on from file and create a new BMediaAddOn class, or 1063 // reuse the cached BMediaAddOn from a previous call 1064 // call BMediaAddOn::InstantiateNodeFor() 1065 // and cache the BMediaAddOn after that for later reuse. 1066 // BeOS R5 does not seem to delete it when the application quits 1067 // if B_FLAVOR_IS_GLOBAL, we need to use the BMediaAddOn object that 1068 // resides in the media_addon_server 1069 1070 // RegisterNode() is called automatically for nodes instantiated from add-ons 1071 1072 //XXX TEST! 1073 BMediaAddOn *addon; 1074 BMediaNode *node; 1075 BMessage config; 1076 status_t out_error; 1077 status_t rv; 1078 addon = _DormantNodeManager->GetAddon(in_info.addon); 1079 if (!addon) { 1080 printf("BMediaRoster::InstantiateDormantNode: GetAddon failed\n"); 1081 return B_ERROR; 1082 } 1083 flavor_info temp; 1084 temp.internal_id = in_info.flavor_id; 1085 node = addon->InstantiateNodeFor(&temp, &config, &out_error); 1086 if (!node) { 1087 printf("BMediaRoster::InstantiateDormantNode: InstantiateNodeFor failed\n"); 1088 _DormantNodeManager->PutAddon(in_info.addon); 1089 return B_ERROR; 1090 } 1091 rv = RegisterNode(node); 1092 if (rv != B_OK) { 1093 printf("BMediaRoster::InstantiateDormantNode: RegisterNode failed\n"); 1094 delete node; 1095 _DormantNodeManager->PutAddon(in_info.addon); 1096 return B_ERROR; 1097 } 1098 1099 // XXX we must remember in_info.addon and call 1100 // XXX _DormantNodeManager->PutAddon when the 1101 // XXX node is unregistered 1102 1103 *out_node = node->Node(); 1104 return B_OK; 1105 } 1106 1107 1108 status_t 1109 BMediaRoster::GetDormantNodeFor(const media_node & node, 1110 dormant_node_info * out_info) 1111 { 1112 UNIMPLEMENTED(); 1113 1114 return B_ERROR; 1115 } 1116 1117 1118 status_t 1119 BMediaRoster::GetDormantFlavorInfoFor(const dormant_node_info & in_dormant, 1120 dormant_flavor_info * out_flavor) 1121 { 1122 CALLED(); 1123 1124 xfer_server_get_dormant_flavor_info msg; 1125 xfer_server_get_dormant_flavor_info_reply *reply; 1126 port_id port; 1127 status_t rv; 1128 int32 code; 1129 1130 port = find_port("media_server port"); 1131 if (port <= B_OK) 1132 return B_ERROR; 1133 1134 reply = (xfer_server_get_dormant_flavor_info_reply *) malloc(16000); 1135 if (reply == 0) 1136 return B_ERROR; 1137 1138 msg.addon = in_dormant.addon; 1139 msg.flavor_id = in_dormant.flavor_id; 1140 msg.reply_port = _PortPool->GetPort(); 1141 rv = write_port(port, SERVER_GET_DORMANT_FLAVOR_INFO, &msg, sizeof(msg)); 1142 if (rv != B_OK) { 1143 free(reply); 1144 _PortPool->PutPort(msg.reply_port); 1145 return rv; 1146 } 1147 rv = read_port(msg.reply_port, &code, reply, 16000); 1148 _PortPool->PutPort(msg.reply_port); 1149 1150 if (rv < B_OK) { 1151 free(reply); 1152 return rv; 1153 } 1154 1155 if (reply->result == B_OK) 1156 rv = out_flavor->Unflatten(reply->dfi_type, &reply->dfi, reply->dfi_size); 1157 else 1158 rv = reply->result; 1159 1160 free(reply); 1161 return rv; 1162 } 1163 1164 1165 status_t 1166 BMediaRoster::GetLatencyFor(const media_node & producer, 1167 bigtime_t * out_latency) 1168 { 1169 UNIMPLEMENTED(); 1170 *out_latency = 0; 1171 return B_ERROR; 1172 } 1173 1174 1175 status_t 1176 BMediaRoster::GetInitialLatencyFor(const media_node & producer, 1177 bigtime_t * out_latency, 1178 uint32 * out_flags) 1179 { 1180 UNIMPLEMENTED(); 1181 *out_latency = 0; 1182 *out_flags = 0; 1183 return B_ERROR; 1184 } 1185 1186 1187 status_t 1188 BMediaRoster::GetStartLatencyFor(const media_node & time_source, 1189 bigtime_t * out_latency) 1190 { 1191 UNIMPLEMENTED(); 1192 *out_latency = 0; 1193 return B_ERROR; 1194 } 1195 1196 1197 status_t 1198 BMediaRoster::GetFileFormatsFor(const media_node & file_interface, 1199 media_file_format * out_formats, 1200 int32 * io_num_infos) 1201 { 1202 UNIMPLEMENTED(); 1203 return B_ERROR; 1204 } 1205 1206 1207 status_t 1208 BMediaRoster::SetRefFor(const media_node & file_interface, 1209 const entry_ref & file, 1210 bool create_and_truncate, 1211 bigtime_t * out_length) /* if create is false */ 1212 { 1213 UNIMPLEMENTED(); 1214 return B_ERROR; 1215 } 1216 1217 1218 status_t 1219 BMediaRoster::GetRefFor(const media_node & node, 1220 entry_ref * out_file, 1221 BMimeType * mime_type) 1222 { 1223 UNIMPLEMENTED(); 1224 return B_ERROR; 1225 } 1226 1227 1228 status_t 1229 BMediaRoster::SniffRefFor(const media_node & file_interface, 1230 const entry_ref & file, 1231 BMimeType * mime_type, 1232 float * out_capability) 1233 { 1234 UNIMPLEMENTED(); 1235 return B_ERROR; 1236 } 1237 1238 1239 /* This is the generic "here's a file, now can someone please play it" interface */ 1240 status_t 1241 BMediaRoster::SniffRef(const entry_ref & file, 1242 uint64 require_node_kinds, /* if you need an EntityInterface or BufferConsumer or something */ 1243 dormant_node_info * out_node, 1244 BMimeType * mime_type) 1245 { 1246 UNIMPLEMENTED(); 1247 return B_ERROR; 1248 } 1249 1250 1251 status_t 1252 BMediaRoster::GetDormantNodeForType(const BMimeType & type, 1253 uint64 require_node_kinds, 1254 dormant_node_info * out_node) 1255 { 1256 UNIMPLEMENTED(); 1257 return B_ERROR; 1258 } 1259 1260 1261 status_t 1262 BMediaRoster::GetReadFileFormatsFor(const dormant_node_info & in_node, 1263 media_file_format * out_read_formats, 1264 int32 in_read_count, 1265 int32 * out_read_count) 1266 { 1267 UNIMPLEMENTED(); 1268 return B_ERROR; 1269 } 1270 1271 1272 status_t 1273 BMediaRoster::GetWriteFileFormatsFor(const dormant_node_info & in_node, 1274 media_file_format * out_write_formats, 1275 int32 in_write_count, 1276 int32 * out_write_count) 1277 { 1278 UNIMPLEMENTED(); 1279 return B_ERROR; 1280 } 1281 1282 1283 status_t 1284 BMediaRoster::GetFormatFor(const media_output & output, 1285 media_format * io_format, 1286 uint32 flags) 1287 { 1288 UNIMPLEMENTED(); 1289 return B_ERROR; 1290 } 1291 1292 1293 status_t 1294 BMediaRoster::GetFormatFor(const media_input & input, 1295 media_format * io_format, 1296 uint32 flags) 1297 { 1298 UNIMPLEMENTED(); 1299 return B_ERROR; 1300 } 1301 1302 1303 status_t 1304 BMediaRoster::GetFormatFor(const media_node & node, 1305 media_format * io_format, 1306 float quality) 1307 { 1308 UNIMPLEMENTED(); 1309 return B_ERROR; 1310 } 1311 1312 1313 ssize_t 1314 BMediaRoster::GetNodeAttributesFor(const media_node & node, 1315 media_node_attribute * outArray, 1316 size_t inMaxCount) 1317 { 1318 UNIMPLEMENTED(); 1319 return B_ERROR; 1320 } 1321 1322 1323 media_node_id 1324 BMediaRoster::NodeIDFor(port_id source_or_destination_port) 1325 { 1326 UNIMPLEMENTED(); 1327 return B_ERROR; 1328 } 1329 1330 1331 status_t 1332 BMediaRoster::GetInstancesFor(media_addon_id addon, 1333 int32 flavor, 1334 media_node_id * out_id, 1335 int32 * io_count) 1336 { 1337 UNIMPLEMENTED(); 1338 return B_ERROR; 1339 } 1340 1341 1342 1343 status_t 1344 BMediaRoster::SetRealtimeFlags(uint32 in_enabled) 1345 { 1346 UNIMPLEMENTED(); 1347 return B_ERROR; 1348 } 1349 1350 1351 status_t 1352 BMediaRoster::GetRealtimeFlags(uint32 * out_enabled) 1353 { 1354 UNIMPLEMENTED(); 1355 return B_ERROR; 1356 } 1357 1358 1359 ssize_t 1360 BMediaRoster::AudioBufferSizeFor(int32 channel_count, 1361 uint32 sample_format, 1362 float frame_rate, 1363 bus_type bus_kind) 1364 { 1365 UNIMPLEMENTED(); 1366 return 4096; 1367 } 1368 1369 1370 /* Use MediaFlags to inquire about specific features of the Media Kit. */ 1371 /* Returns < 0 for "not present", positive size for output data size. */ 1372 /* 0 means that the capability is present, but no data about it. */ 1373 /* static */ ssize_t 1374 BMediaRoster::MediaFlags(media_flags cap, 1375 void * buf, 1376 size_t maxSize) 1377 { 1378 UNIMPLEMENTED(); 1379 return 0; 1380 } 1381 1382 1383 1384 /* BLooper overrides */ 1385 /* virtual */ void 1386 BMediaRoster::MessageReceived(BMessage * message) 1387 { 1388 UNIMPLEMENTED(); 1389 } 1390 1391 /* virtual */ bool 1392 BMediaRoster::QuitRequested() 1393 { 1394 UNIMPLEMENTED(); 1395 return true; 1396 } 1397 1398 /* virtual */ BHandler * 1399 BMediaRoster::ResolveSpecifier(BMessage *msg, 1400 int32 index, 1401 BMessage *specifier, 1402 int32 form, 1403 const char *property) 1404 { 1405 UNIMPLEMENTED(); 1406 return 0; 1407 } 1408 1409 1410 /* virtual */ status_t 1411 BMediaRoster::GetSupportedSuites(BMessage *data) 1412 { 1413 UNIMPLEMENTED(); 1414 return B_ERROR; 1415 } 1416 1417 1418 BMediaRoster::~BMediaRoster() 1419 { 1420 CALLED(); 1421 BMessage msg(MEDIA_SERVER_UNREGISTER_APP); 1422 BMessage reply; 1423 msg.AddInt32("team",team); 1424 QueryServer(&msg, &reply); 1425 } 1426 1427 1428 /************************************************************* 1429 * private BMediaRoster 1430 *************************************************************/ 1431 1432 // deprecated call 1433 status_t 1434 BMediaRoster::SetOutputBuffersFor(const media_source & output, 1435 BBufferGroup * group, 1436 bool will_reclaim ) 1437 { 1438 UNIMPLEMENTED(); 1439 return B_ERROR; 1440 } 1441 1442 1443 /* FBC stuffing (Mmmh, Stuffing!) */ 1444 status_t BMediaRoster::_Reserved_MediaRoster_0(void *) { return B_ERROR; } 1445 status_t BMediaRoster::_Reserved_MediaRoster_1(void *) { return B_ERROR; } 1446 status_t BMediaRoster::_Reserved_MediaRoster_2(void *) { return B_ERROR; } 1447 status_t BMediaRoster::_Reserved_MediaRoster_3(void *) { return B_ERROR; } 1448 status_t BMediaRoster::_Reserved_MediaRoster_4(void *) { return B_ERROR; } 1449 status_t BMediaRoster::_Reserved_MediaRoster_5(void *) { return B_ERROR; } 1450 status_t BMediaRoster::_Reserved_MediaRoster_6(void *) { return B_ERROR; } 1451 status_t BMediaRoster::_Reserved_MediaRoster_7(void *) { return B_ERROR; } 1452 1453 1454 BMediaRoster::BMediaRoster() : 1455 BLooper("BMediaRoster looper",B_NORMAL_PRIORITY,B_LOOPER_PORT_DEFAULT_CAPACITY) 1456 { 1457 CALLED(); 1458 BMessage msg(MEDIA_SERVER_REGISTER_APP); 1459 BMessage reply; 1460 msg.AddInt32("team",team); 1461 QueryServer(&msg,&reply); 1462 } 1463 1464 /* static */ status_t 1465 BMediaRoster::ParseCommand(BMessage & reply) 1466 { 1467 UNIMPLEMENTED(); 1468 return B_ERROR; 1469 } 1470 1471 1472 1473 status_t 1474 BMediaRoster::GetDefaultInfo(media_node_id for_default, 1475 BMessage & out_config) 1476 { 1477 UNIMPLEMENTED(); 1478 return B_ERROR; 1479 } 1480 1481 1482 1483 status_t 1484 BMediaRoster::SetRunningDefault(media_node_id for_default, 1485 const media_node & node) 1486 { 1487 UNIMPLEMENTED(); 1488 return B_ERROR; 1489 } 1490 1491 1492 /************************************************************* 1493 * static BMediaRoster variables 1494 *************************************************************/ 1495 1496 bool BMediaRoster::_isMediaServer; 1497 port_id BMediaRoster::_mReplyPort; 1498 int32 BMediaRoster::_mReplyPortRes; 1499 int32 BMediaRoster::_mReplyPortUnavailCount; 1500 BMediaRoster * BMediaRoster::_sDefault = NULL; 1501 1502