1 /*********************************************************************** 2 * AUTHOR: Marcus Overhagen 3 * FILE: MediaNode.cpp 4 * DESCR: 5 ***********************************************************************/ 6 #include <MediaRoster.h> 7 #include <MediaNode.h> 8 #include <TimeSource.h> 9 #include <BufferConsumer.h> 10 #include <BufferProducer.h> 11 #include <Controllable.h> 12 #include <FileInterface.h> 13 #include <string.h> 14 #define DEBUG 3 15 #include <Debug.h> 16 #include "debug.h" 17 #include "DataExchange.h" 18 #include "SystemTimeSource.h" 19 #include "ServerInterface.h" 20 #include "Notifications.h" 21 22 // don't rename this one, it's used and exported for binary compatibility 23 int32 BMediaNode::_m_changeTag = 0; 24 25 /************************************************************* 26 * media_node 27 *************************************************************/ 28 29 // final & verified 30 media_node::media_node() 31 : node(-1), 32 port(-1), 33 kind(0) 34 { 35 } 36 37 // final & verified 38 media_node::~media_node() 39 { 40 } 41 42 /************************************************************* 43 * static media_node variables 44 *************************************************************/ 45 46 // final & verified 47 media_node media_node::null; 48 49 /************************************************************* 50 * media_input 51 *************************************************************/ 52 53 // final 54 media_input::media_input() 55 { 56 name[0] = '\0'; 57 } 58 59 // final 60 media_input::~media_input() 61 { 62 } 63 64 /************************************************************* 65 * media_output 66 *************************************************************/ 67 68 // final 69 media_output::media_output() 70 { 71 name[0] = '\0'; 72 } 73 74 // final 75 media_output::~media_output() 76 { 77 } 78 79 /************************************************************* 80 * live_node_info 81 *************************************************************/ 82 83 // final & verified 84 live_node_info::live_node_info() 85 : hint_point(0.0f,0.0f) 86 { 87 name[0] = '\0'; 88 } 89 90 // final & verified 91 live_node_info::~live_node_info() 92 { 93 } 94 95 /************************************************************* 96 * protected BMediaNode 97 *************************************************************/ 98 99 /* virtual */ 100 BMediaNode::~BMediaNode() 101 { 102 CALLED(); 103 104 // BeBook: UnregisterNode() unregisters a node from the Media Server. It's called automatically 105 // BeBook: by the BMediaNode destructor, but it might be convenient to call it sometime before 106 // BeBook: you delete your node instance, depending on your implementation and circumstances. 107 (BMediaRoster::Roster())->UnregisterNode(this); 108 109 if (fControlPort != -1) 110 delete_port(fControlPort); 111 if (fTimeSource) 112 fTimeSource->Release(); 113 } 114 115 /************************************************************* 116 * public BMediaNode 117 *************************************************************/ 118 119 BMediaNode * 120 BMediaNode::Acquire() 121 { 122 CALLED(); 123 atomic_add(&fRefCount,1); 124 return this; 125 } 126 127 128 BMediaNode * 129 BMediaNode::Release() 130 { 131 CALLED(); 132 if (atomic_add(&fRefCount,-1) == 1) { 133 if (DeleteHook(this) != B_OK) { 134 TRACE("BMediaNode::Release(): DeleteHook failed\n"); 135 return Acquire(); 136 } 137 return NULL; 138 } 139 return this; 140 } 141 142 143 const char * 144 BMediaNode::Name() const 145 { 146 CALLED(); 147 return fName; 148 } 149 150 151 media_node_id 152 BMediaNode::ID() const 153 { 154 CALLED(); 155 return fNodeID; 156 } 157 158 159 uint64 160 BMediaNode::Kinds() const 161 { 162 CALLED(); 163 return fKinds; 164 } 165 166 167 media_node 168 BMediaNode::Node() const 169 { 170 CALLED(); 171 media_node temp; 172 temp.node = ID(); 173 temp.port = ControlPort(); 174 temp.kind = Kinds(); 175 return temp; 176 } 177 178 179 BMediaNode::run_mode 180 BMediaNode::RunMode() const 181 { 182 CALLED(); 183 return fRunMode; 184 } 185 186 187 BTimeSource * 188 BMediaNode::TimeSource() const 189 { 190 CALLED(); 191 if (fTimeSource == 0) 192 const_cast<BMediaNode *>(this)->fTimeSource = new _SysTimeSource; 193 return fTimeSource; 194 } 195 196 197 /* virtual */ port_id 198 BMediaNode::ControlPort() const 199 { 200 CALLED(); 201 return fControlPort; 202 } 203 204 205 /************************************************************* 206 * protected BMediaNode 207 *************************************************************/ 208 209 status_t 210 BMediaNode::ReportError(node_error what, 211 const BMessage *info) 212 { 213 CALLED(); 214 215 // sanity check the what value 216 switch (what) { 217 case BMediaNode::B_NODE_FAILED_START: 218 case BMediaNode::B_NODE_FAILED_STOP: 219 case BMediaNode::B_NODE_FAILED_SEEK: 220 case BMediaNode::B_NODE_FAILED_SET_RUN_MODE: 221 case BMediaNode::B_NODE_FAILED_TIME_WARP: 222 case BMediaNode::B_NODE_FAILED_PREROLL: 223 case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR: 224 case BMediaNode::B_NODE_IN_DISTRESS: 225 break; 226 default: 227 TRACE("BMediaNode::ReportError: invalid what!\n"); 228 return B_BAD_VALUE; 229 } 230 231 // Transmits the error code specified by what to anyone 232 // that's receiving notifications from this node 233 return BPrivate::media::notifications::ReportError(Node(), what, info); 234 } 235 236 237 status_t 238 BMediaNode::NodeStopped(bigtime_t whenPerformance) 239 { 240 UNIMPLEMENTED(); 241 // called by derived classes when they have 242 // finished handling a stop request. 243 244 // notify anyone who is listening for stop notifications! 245 BPrivate::media::notifications::NodeStopped(Node(), whenPerformance); 246 247 // XXX If your node is a BBufferProducer, downstream consumers 248 // XXX will be notified that your node stopped (automatically, no less) 249 // XXX through the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call. 250 251 return B_OK; 252 } 253 254 255 void 256 BMediaNode::TimerExpired(bigtime_t notifyPoint, 257 int32 cookie, 258 status_t error) 259 { 260 UNIMPLEMENTED(); 261 // Used with AddTimer 262 // This will, in turn, cause the BMediaRoster::SyncToNode() call 263 // that instigated the timer to return to the caller. 264 // Probably only important to classes derived from BTimeSource. 265 } 266 267 268 /* explicit */ 269 BMediaNode::BMediaNode(const char *name) 270 { 271 TRACE("BMediaNode::BMediaNode: name '%s'\n", name); 272 _InitObject(name, -1, 0); 273 } 274 275 276 status_t 277 BMediaNode::WaitForMessage(bigtime_t waitUntil, 278 uint32 flags, 279 void *_reserved_) 280 { 281 CALLED(); 282 ASSERT(this != 0); 283 // This function waits until either real time specified by 284 // waitUntil or a message is received on the control port. 285 // The flags are currently unused and should be 0. 286 287 char data[B_MEDIA_MESSAGE_SIZE]; // about 16 KByte stack used 288 int32 message; 289 ssize_t size; 290 291 size = read_port_etc(fControlPort, &message, data, sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil); 292 if (size <= 0) { 293 if (size != B_TIMED_OUT) 294 TRACE("BMediaNode::WaitForMessage: read_port_etc error 0x%08lx\n",size); 295 return size; // returns the error code 296 } 297 298 TRACE("BMediaNode::WaitForMessage %#lx, node %ld, this %p\n", message, fNodeID, this); 299 300 if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { 301 TRACE("BMediaNode::WaitForMessage calling BMediaNode\n"); 302 if (B_OK == BMediaNode::HandleMessage(message, data, size)) 303 return B_OK; 304 } 305 306 if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) { 307 if (!fProducerThis) 308 fProducerThis = dynamic_cast<BBufferProducer *>(this); 309 TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", fProducerThis); 310 if (fProducerThis && B_OK == fProducerThis->BBufferProducer::HandleMessage(message, data, size)) 311 return B_OK; 312 } 313 314 if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) { 315 if (!fConsumerThis) 316 fConsumerThis = dynamic_cast<BBufferConsumer *>(this); 317 TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", fConsumerThis); 318 if (fConsumerThis && B_OK == fConsumerThis->BBufferConsumer::HandleMessage(message, data, size)) 319 return B_OK; 320 } 321 322 if (message > FILEINTERFACE_MESSAGE_START && message < FILEINTERFACE_MESSAGE_END) { 323 if (!fFileInterfaceThis) 324 fFileInterfaceThis = dynamic_cast<BFileInterface *>(this); 325 TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", fFileInterfaceThis); 326 if (fFileInterfaceThis && B_OK == fFileInterfaceThis->BFileInterface::HandleMessage(message, data, size)) 327 return B_OK; 328 } 329 330 if (fControllableThis && message > CONTROLLABLE_MESSAGE_START && message < CONTROLLABLE_MESSAGE_END) { 331 if (!fControllableThis) 332 fControllableThis = dynamic_cast<BControllable *>(this); 333 TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", fControllableThis); 334 if (fControllableThis && B_OK == fControllableThis->BControllable::HandleMessage(message, data, size)) 335 return B_OK; 336 } 337 338 if (fTimeSourceThis && message > TIMESOURECE_MESSAGE_START && message < TIMESOURECE_MESSAGE_END) { 339 if (!fTimeSourceThis) 340 fTimeSourceThis = dynamic_cast<BTimeSource *>(this); 341 TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", fTimeSourceThis); 342 if (fTimeSourceThis && B_OK == fTimeSourceThis->BTimeSource::HandleMessage(message, data, size)) 343 return B_OK; 344 } 345 346 TRACE("BMediaNode::WaitForMessage calling default\n"); 347 if (B_OK == HandleMessage(message, data, size)) 348 return B_OK; 349 350 HandleBadMessage(message, data, size); 351 352 return B_ERROR; 353 } 354 355 356 /* virtual */ void 357 BMediaNode::Start(bigtime_t performance_time) 358 { 359 CALLED(); 360 // This hook function is called when a node is started 361 // by a call to the BMediaRoster. The specified 362 // performanceTime, the time at which the node 363 // should start running, may be in the future. 364 // It may be overriden by derived classes. 365 // The BMediaEventLooper class handles this event! 366 // The BMediaNode class does nothing here. 367 } 368 369 370 /* virtual */ void 371 BMediaNode::Stop(bigtime_t performance_time, 372 bool immediate) 373 { 374 CALLED(); 375 // This hook function is called when a node is stopped 376 // by a call to the BMediaRoster. The specified 377 // performanceTime, the time at which the node 378 // should stop running, may be in the future. 379 // It may be overriden by derived classes. 380 // The BMediaEventLooper class handles this event! 381 // The BMediaNode class does nothing here. 382 } 383 384 385 /* virtual */ void 386 BMediaNode::Seek(bigtime_t media_time, 387 bigtime_t performance_time) 388 { 389 CALLED(); 390 // This hook function is called when a node is asked 391 // to seek to the specified mediaTime by a call to 392 // the BMediaRoster. The specified performanceTime, 393 // the time at which the node should begin the seek 394 // operation, may be in the future. 395 // It may be overriden by derived classes. 396 // The BMediaEventLooper class handles this event! 397 // The BMediaNode class does nothing here. 398 } 399 400 401 /* virtual */ void 402 BMediaNode::SetRunMode(run_mode mode) 403 { 404 CALLED(); 405 406 // this is a hook function, and 407 // may be overriden by derived classes. 408 409 // the functionality here is only to 410 // support those people that don't 411 // use the roster to set the run mode 412 fRunMode = mode; 413 } 414 415 416 /* virtual */ void 417 BMediaNode::TimeWarp(bigtime_t at_real_time, 418 bigtime_t to_performance_time) 419 { 420 CALLED(); 421 // May be overriden by derived classes. 422 } 423 424 425 /* virtual */ void 426 BMediaNode::Preroll() 427 { 428 CALLED(); 429 // May be overriden by derived classes. 430 } 431 432 433 /* virtual */ void 434 BMediaNode::SetTimeSource(BTimeSource *time_source) 435 { 436 CALLED(); 437 return;// XXX 438 439 // this is a hook function, and 440 // may be overriden by derived classes. 441 442 // the functionality here is only to 443 // support those people that don't 444 // use the roster to set a time source 445 if (time_source == fTimeSource) 446 return; 447 if (time_source == NULL) 448 return; 449 if (fTimeSource) 450 fTimeSource->Release(); 451 fTimeSource = dynamic_cast<BTimeSource *>(time_source->Acquire()); 452 fTimeSourceID = fTimeSource->ID(); 453 } 454 455 /************************************************************* 456 * public BMediaNode 457 *************************************************************/ 458 459 /* virtual */ status_t 460 BMediaNode::HandleMessage(int32 message, 461 const void *data, 462 size_t size) 463 { 464 // CALLED(); 465 TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID); 466 switch (message) { 467 case NODE_START: 468 { 469 const xfer_node_start *request = (const xfer_node_start *)data; 470 Start(request->performance_time); 471 return B_OK; 472 } 473 474 case NODE_STOP: 475 { 476 const xfer_node_stop *request = (const xfer_node_stop *)data; 477 Stop(request->performance_time, request->immediate); 478 return B_OK; 479 } 480 481 case NODE_SEEK: 482 { 483 const xfer_node_seek *request = (const xfer_node_seek *)data; 484 Seek(request->media_time, request->performance_time); 485 return B_OK; 486 } 487 488 case NODE_SET_RUN_MODE: 489 { 490 const xfer_node_set_run_mode *request = (const xfer_node_set_run_mode *)data; 491 fRunMode = request->mode; 492 SetRunMode(fRunMode); 493 return B_OK; 494 } 495 496 case NODE_TIME_WARP: 497 { 498 const xfer_node_time_warp *request = (const xfer_node_time_warp *)data; 499 TimeWarp(request->at_real_time,request->to_performance_time); 500 return B_OK; 501 } 502 503 case NODE_PREROLL: 504 { 505 Preroll(); 506 return B_OK; 507 } 508 509 case NODE_SET_TIMESOURCE: 510 { 511 const xfer_node_set_timesource *request = (const xfer_node_set_timesource *)data; 512 bool first = (fTimeSourceID == 0); 513 if (fTimeSource) 514 fTimeSource->Release(); 515 fTimeSourceID = request->timesource_id; 516 fTimeSource = 0; // XXX create timesource object here 517 fTimeSource = new _SysTimeSource; 518 if (!first) 519 SetTimeSource(fTimeSource); 520 return B_OK; 521 } 522 523 case NODE_REQUEST_COMPLETED: 524 { 525 const xfer_node_request_completed *request = (const xfer_node_request_completed *)data; 526 RequestCompleted(request->info); 527 return B_OK; 528 } 529 530 }; 531 return B_ERROR; 532 } 533 534 535 void 536 BMediaNode::HandleBadMessage(int32 code, 537 const void *buffer, 538 size_t size) 539 { 540 CALLED(); 541 542 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size); 543 if (code < NODE_MESSAGE_START || code > TIMESOURECE_MESSAGE_END) { 544 TRACE("BMediaNode::HandleBadMessage: unknown code!\n"); 545 } else { 546 /* All messages targeted to nodes should be handled here, 547 * messages targetted to the wrong node should be handled 548 * by returning an error, not by stalling the sender. 549 */ 550 const request_data *request = static_cast<const request_data *>(buffer); 551 reply_data reply; 552 request->SendReply(B_ERROR, &reply, sizeof(reply)); 553 } 554 } 555 556 557 void 558 BMediaNode::AddNodeKind(uint64 kind) 559 { 560 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 561 562 fKinds |= kind; 563 } 564 565 566 void * 567 BMediaNode::operator new(size_t size) 568 { 569 CALLED(); 570 return ::operator new(size); 571 } 572 573 void * 574 BMediaNode::operator new(size_t size, 575 const nothrow_t &) throw() 576 { 577 CALLED(); 578 return ::operator new(size, nothrow); 579 } 580 581 void 582 BMediaNode::operator delete(void *ptr) 583 { 584 CALLED(); 585 ::operator delete(ptr); 586 } 587 588 void 589 BMediaNode::operator delete(void * ptr, 590 const nothrow_t &) throw() 591 { 592 CALLED(); 593 ::operator delete(ptr, nothrow); 594 } 595 596 /************************************************************* 597 * protected BMediaNode 598 *************************************************************/ 599 600 /* virtual */ status_t 601 BMediaNode::RequestCompleted(const media_request_info &info) 602 { 603 CALLED(); 604 // This function is called whenever a request issued by the node is completed. 605 // May be overriden by derived classes. 606 // info.change_tag can be used to match up requests against 607 // the accompaning calles from 608 // BBufferConsumer::RequestFormatChange() 609 // BBufferConsumer::SetOutputBuffersFor() 610 // BBufferConsumer::SetOutputEnabled() 611 // BBufferConsumer::SetVideoClippingFor() 612 return B_OK; 613 } 614 615 /************************************************************* 616 * private BMediaNode 617 *************************************************************/ 618 619 int32 620 BMediaNode::IncrementChangeTag() 621 { 622 CALLED(); 623 // Only present in BeOS R4 624 // Obsoleted in BeOS R4.5 and later 625 // "updates the change tag, so that downstream consumers know that the node is in a new state." 626 // not supported, only for binary compatibility 627 return 0; 628 } 629 630 631 int32 632 BMediaNode::ChangeTag() 633 { 634 UNIMPLEMENTED(); 635 // Only present in BeOS R4 636 // Obsoleted in BeOS R4.5 and later 637 // "returns the node's current change tag value." 638 // not supported, only for binary compatibility 639 return 0; 640 } 641 642 643 int32 644 BMediaNode::MintChangeTag() 645 { 646 UNIMPLEMENTED(); 647 // Only present in BeOS R4 648 // Obsoleted in BeOS R4.5 and later 649 // "mints a new, reserved, change tag." 650 // "Call ApplyChangeTag() to apply it to the node" 651 // not supported, only for binary compatibility 652 return 0; 653 } 654 655 656 status_t 657 BMediaNode::ApplyChangeTag(int32 previously_reserved) 658 { 659 UNIMPLEMENTED(); 660 // Only present in BeOS R4 661 // Obsoleted in BeOS R4.5 and later 662 // "this returns B_OK if the new change tag is" 663 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 664 // "count you tried to apply is already obsolete." 665 // not supported, only for binary compatibility 666 return B_OK; 667 } 668 669 /************************************************************* 670 * protected BMediaNode 671 *************************************************************/ 672 673 /* virtual */ status_t 674 BMediaNode::DeleteHook(BMediaNode *node) 675 { 676 CALLED(); 677 delete this; // delete "this" or "node" ??? 678 return B_OK; 679 } 680 681 682 /* virtual */ void 683 BMediaNode::NodeRegistered() 684 { 685 CALLED(); 686 // The Media Server calls this hook function after the node has been registered. 687 // May be overriden by derived classes. 688 } 689 690 /************************************************************* 691 * public BMediaNode 692 *************************************************************/ 693 694 /* virtual */ status_t 695 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes, 696 size_t inMaxCount) 697 { 698 UNIMPLEMENTED(); 699 700 return B_ERROR; 701 } 702 703 704 /* virtual */ status_t 705 BMediaNode::AddTimer(bigtime_t at_performance_time, 706 int32 cookie) 707 { 708 UNIMPLEMENTED(); 709 710 return B_ERROR; 711 } 712 713 714 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; } 715 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; } 716 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; } 717 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; } 718 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; } 719 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; } 720 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; } 721 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; } 722 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; } 723 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; } 724 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; } 725 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; } 726 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; } 727 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; } 728 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; } 729 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; } 730 731 /* 732 private unimplemented 733 BMediaNode::BMediaNode() 734 BMediaNode::BMediaNode(const BMediaNode &clone) 735 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 736 */ 737 738 void 739 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) 740 { 741 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 742 743 fNodeID = id; 744 fTimeSource = 0; 745 fRefCount = 1; 746 fName[0] = 0; 747 if (name) { 748 strncpy(fName, name, B_MEDIA_NAME_LENGTH - 1); 749 fName[B_MEDIA_NAME_LENGTH - 1] = 0; 750 } 751 fRunMode = B_INCREASE_LATENCY; 752 _mChangeCount = 0; // deprecated 753 _mChangeCountReserved = 0; // deprecated 754 fKinds = kinds; 755 fTimeSourceID = -1; 756 fProducerThis = 0; 757 fConsumerThis = 0; 758 fFileInterfaceThis = 0; 759 fControllableThis = 0; 760 fTimeSourceThis = 0; 761 762 // create control port 763 fControlPort = create_port(64,fName); 764 } 765 766 767 BMediaNode::BMediaNode(const char *name, 768 media_node_id id, 769 uint32 kinds) 770 { 771 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds); 772 _InitObject(name, id, kinds); 773 } 774 775 776 /************************************************************* 777 * protected BMediaNode 778 *************************************************************/ 779 780 /* static */ int32 781 BMediaNode::NewChangeTag() 782 { 783 CALLED(); 784 // change tags have been used in BeOS R4 to match up 785 // format change requests between producer and consumer, 786 // This has changed starting with R4.5 787 // now "change tags" are used with 788 // BMediaNode::RequestCompleted() 789 // and 790 // BBufferConsumer::RequestFormatChange() 791 // BBufferConsumer::SetOutputBuffersFor() 792 // BBufferConsumer::SetOutputEnabled() 793 // BBufferConsumer::SetVideoClippingFor() 794 return atomic_add(&BMediaNode::_m_changeTag,1); 795 } 796 797 798