1 /* 2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files or portions 6 * thereof (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, merge, 8 * publish, distribute, sublicense, and/or sell copies of the Software, 9 * and to permit persons to whom the Software is furnished to do so, subject 10 * to the following conditions: 11 * 12 * * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * * Redistributions in binary form must reproduce the above copyright notice 16 * in the binary, as well as this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided with 18 * the distribution. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 * THE SOFTWARE. 27 * 28 */ 29 //#define DEBUG 7 30 #include <MediaRoster.h> 31 #include <MediaNode.h> 32 #include <TimeSource.h> 33 #include <BufferConsumer.h> 34 #include <BufferProducer.h> 35 #include <Controllable.h> 36 #include <FileInterface.h> 37 #include <string.h> 38 #include "debug.h" 39 #include "MediaMisc.h" 40 #include "MediaRosterEx.h" 41 #include "DataExchange.h" 42 #include "ServerInterface.h" 43 #include "Notifications.h" 44 #include "TimeSourceObject.h" 45 #include "TimeSourceObjectManager.h" 46 47 using std::nothrow; 48 using std::nothrow_t; 49 50 #undef TRACE 51 //#define TRACE_MEDIA_NODE 52 #ifdef TRACE_MEDIA_NODE 53 #define TRACE printf 54 #else 55 #define TRACE(x...) 56 #endif 57 58 59 // don't rename this one, it's used and exported for binary compatibility 60 int32 BMediaNode::_m_changeTag = 0; 61 62 /************************************************************* 63 * media_node 64 *************************************************************/ 65 66 // final & verified 67 media_node::media_node() 68 : node(-1), 69 port(-1), 70 kind(0) 71 { 72 } 73 74 // final & verified 75 media_node::~media_node() 76 { 77 } 78 79 /************************************************************* 80 * static media_node variables 81 *************************************************************/ 82 83 // final & verified 84 media_node media_node::null; 85 86 /************************************************************* 87 * media_input 88 *************************************************************/ 89 90 // final 91 media_input::media_input() 92 { 93 name[0] = '\0'; 94 } 95 96 // final 97 media_input::~media_input() 98 { 99 } 100 101 /************************************************************* 102 * media_output 103 *************************************************************/ 104 105 // final 106 media_output::media_output() 107 { 108 name[0] = '\0'; 109 } 110 111 // final 112 media_output::~media_output() 113 { 114 } 115 116 /************************************************************* 117 * live_node_info 118 *************************************************************/ 119 120 // final & verified 121 live_node_info::live_node_info() 122 : hint_point(0.0f, 0.0f) 123 { 124 name[0] = '\0'; 125 } 126 127 // final & verified 128 live_node_info::~live_node_info() 129 { 130 } 131 132 /************************************************************* 133 * protected BMediaNode 134 *************************************************************/ 135 136 /* virtual */ 137 BMediaNode::~BMediaNode() 138 { 139 CALLED(); 140 // BeBook: UnregisterNode() unregisters a node from the Media Server. It's called automatically 141 // BeBook: by the BMediaNode destructor, but it might be convenient to call it sometime before 142 // BeBook: you delete your node instance, depending on your implementation and circumstances. 143 144 // first we remove the time source 145 if (fTimeSource) { 146 fTimeSource->RemoveMe(this); 147 fTimeSource->Release(); 148 fTimeSource = NULL; 149 } 150 151 // Attention! We do not unregister TimeSourceObject nodes, 152 // or delete their control ports, since they are only a 153 // shadow object, and the real one still exists 154 if (0 == (fKinds & NODE_KIND_SHADOW_TIMESOURCE)) { 155 BMediaRoster::Roster()->UnregisterNode(this); 156 157 if (fControlPort > 0) 158 delete_port(fControlPort); 159 } else { 160 TRACE("BMediaNode::~BMediaNode: shadow timesource, not unregistering\n"); 161 } 162 } 163 164 /************************************************************* 165 * public BMediaNode 166 *************************************************************/ 167 168 BMediaNode * 169 BMediaNode::Acquire() 170 { 171 CALLED(); 172 atomic_add(&fRefCount,1); 173 return this; 174 } 175 176 177 BMediaNode * 178 BMediaNode::Release() 179 { 180 CALLED(); 181 if (atomic_add(&fRefCount, -1) == 1) { 182 TRACE("BMediaNode::Release() saving node %ld configuration\n", fNodeID); 183 MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(this); 184 if (DeleteHook(this) != B_OK) { 185 ERROR("BMediaNode::Release(): DeleteHook failed\n"); 186 return Acquire(); 187 } 188 return NULL; 189 } 190 return this; 191 } 192 193 194 const char * 195 BMediaNode::Name() const 196 { 197 CALLED(); 198 return fName; 199 } 200 201 202 media_node_id 203 BMediaNode::ID() const 204 { 205 CALLED(); 206 return fNodeID; 207 } 208 209 210 uint64 211 BMediaNode::Kinds() const 212 { 213 CALLED(); 214 return fKinds & NODE_KIND_USER_MASK; 215 } 216 217 218 media_node 219 BMediaNode::Node() const 220 { 221 CALLED(); 222 media_node temp; 223 temp.node = ID(); 224 temp.port = ControlPort(); // we *must* call ControlPort(), some derived nodes use it to start the port read thread! 225 temp.kind = Kinds(); 226 return temp; 227 } 228 229 230 BMediaNode::run_mode 231 BMediaNode::RunMode() const 232 { 233 CALLED(); 234 return fRunMode; 235 } 236 237 238 BTimeSource * 239 BMediaNode::TimeSource() const 240 { 241 PRINT(7, "CALLED BMediaNode::TimeSource()\n"); 242 243 // return the currently assigned time source 244 if (fTimeSource != 0) 245 return fTimeSource; 246 247 TRACE("BMediaNode::TimeSource node %ld enter\n", ID()); 248 249 // If the node doesn't have a time source object, we need to create one. 250 // If the node is still unregistered, we can't call MakeTimeSourceFor(), 251 // but since the node does still have the default system time source, we 252 // can use GetSystemTimeSource 253 254 BMediaNode *self = const_cast<BMediaNode *>(this); 255 // if (fTimeSourceID == NODE_SYSTEM_TIMESOURCE_ID) { 256 // self->fTimeSource = _TimeSourceObjectManager->GetSystemTimeSource(); 257 // } else { 258 self->fTimeSource = MediaRosterEx(BMediaRoster::Roster())->MakeTimeSourceObject(fTimeSourceID); 259 // } 260 ASSERT(fTimeSource == self->fTimeSource); 261 262 if (fTimeSource == 0) { 263 ERROR("BMediaNode::TimeSource: MakeTimeSourceFor failed\n"); 264 } else { 265 ASSERT(fTimeSourceID == fTimeSource->ID()); 266 fTimeSource->AddMe(self); 267 } 268 269 TRACE("BMediaNode::TimeSource node %ld leave\n", ID()); 270 271 return fTimeSource; 272 } 273 274 275 /* virtual */ port_id 276 BMediaNode::ControlPort() const 277 { 278 PRINT(7, "CALLED BMediaNode::ControlPort()\n"); 279 return fControlPort; 280 } 281 282 283 /************************************************************* 284 * protected BMediaNode 285 *************************************************************/ 286 287 status_t 288 BMediaNode::ReportError(node_error what, 289 const BMessage *info) 290 { 291 CALLED(); 292 293 // sanity check the what value 294 switch (what) { 295 case BMediaNode::B_NODE_FAILED_START: 296 case BMediaNode::B_NODE_FAILED_STOP: 297 case BMediaNode::B_NODE_FAILED_SEEK: 298 case BMediaNode::B_NODE_FAILED_SET_RUN_MODE: 299 case BMediaNode::B_NODE_FAILED_TIME_WARP: 300 case BMediaNode::B_NODE_FAILED_PREROLL: 301 case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR: 302 case BMediaNode::B_NODE_IN_DISTRESS: 303 break; 304 default: 305 ERROR("BMediaNode::ReportError: invalid what!\n"); 306 return B_BAD_VALUE; 307 } 308 309 // Transmits the error code specified by what to anyone 310 // that's receiving notifications from this node 311 return BPrivate::media::notifications::ReportError(Node(), what, info); 312 } 313 314 315 status_t 316 BMediaNode::NodeStopped(bigtime_t whenPerformance) 317 { 318 UNIMPLEMENTED(); 319 // called by derived classes when they have 320 // finished handling a stop request. 321 322 // notify anyone who is listening for stop notifications! 323 BPrivate::media::notifications::NodeStopped(Node(), whenPerformance); 324 325 // XXX If your node is a BBufferProducer, downstream consumers 326 // XXX will be notified that your node stopped (automatically, no less) 327 // XXX through the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call. 328 329 return B_OK; 330 } 331 332 333 void 334 BMediaNode::TimerExpired(bigtime_t notifyPoint, 335 int32 cookie, 336 status_t error) 337 { 338 UNIMPLEMENTED(); 339 // Used with AddTimer 340 // This will, in turn, cause the BMediaRoster::SyncToNode() call 341 // that instigated the timer to return to the caller. 342 // Probably only important to classes derived from BTimeSource. 343 } 344 345 346 /* explicit */ 347 BMediaNode::BMediaNode(const char *name) 348 { 349 TRACE("BMediaNode::BMediaNode: name '%s'\n", name); 350 _InitObject(name, NODE_JUST_CREATED_ID, 0); 351 } 352 353 354 status_t 355 BMediaNode::WaitForMessage(bigtime_t waitUntil, 356 uint32 flags, 357 void *_reserved_) 358 { 359 TRACE("entering: BMediaNode::WaitForMessage()\n"); 360 361 // This function waits until either real time specified by 362 // waitUntil or a message is received on the control port. 363 // The flags are currently unused and should be 0. 364 365 char data[B_MEDIA_MESSAGE_SIZE]; // about 16 KByte stack used 366 int32 message; 367 ssize_t size = read_port_etc(ControlPort(), &message, data, sizeof(data), 368 B_ABSOLUTE_TIMEOUT, waitUntil); 369 if (size < 0) { 370 status_t error = (status_t)size; 371 if (error != B_TIMED_OUT && error != B_BAD_PORT_ID) 372 ERROR("BMediaNode::WaitForMessage: read_port_etc error: %s\n", 373 strerror(error)); 374 return error; 375 } 376 377 TRACE("BMediaNode::WaitForMessage request is: %#lx, node %ld, this %p\n", 378 message, fNodeID, this); 379 380 if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { 381 TRACE("BMediaNode::WaitForMessage calling BMediaNode\n"); 382 if (B_OK == BMediaNode::HandleMessage(message, data, size)) 383 return B_OK; 384 } 385 386 if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) { 387 if (!fProducerThis) 388 fProducerThis = dynamic_cast<BBufferProducer *>(this); 389 TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", 390 fProducerThis); 391 if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage( 392 message, data, size) == B_OK) { 393 return B_OK; 394 } 395 } 396 397 if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) { 398 if (!fConsumerThis) 399 fConsumerThis = dynamic_cast<BBufferConsumer *>(this); 400 TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", 401 fConsumerThis); 402 if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage( 403 message, data, size) == B_OK) { 404 return B_OK; 405 } 406 } 407 408 if (message > FILEINTERFACE_MESSAGE_START 409 && message < FILEINTERFACE_MESSAGE_END) { 410 if (!fFileInterfaceThis) 411 fFileInterfaceThis = dynamic_cast<BFileInterface *>(this); 412 TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", 413 fFileInterfaceThis); 414 if (fFileInterfaceThis 415 && fFileInterfaceThis->BFileInterface::HandleMessage( 416 message, data, size) == B_OK) { 417 return B_OK; 418 } 419 } 420 421 if (message > CONTROLLABLE_MESSAGE_START 422 && message < CONTROLLABLE_MESSAGE_END) { 423 if (!fControllableThis) 424 fControllableThis = dynamic_cast<BControllable *>(this); 425 TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", 426 fControllableThis); 427 if (fControllableThis 428 && fControllableThis->BControllable::HandleMessage( 429 message, data, size) == B_OK) { 430 return B_OK; 431 } 432 } 433 434 if (message > TIMESOURCE_MESSAGE_START 435 && message < TIMESOURCE_MESSAGE_END) { 436 if (!fTimeSourceThis) 437 fTimeSourceThis = dynamic_cast<BTimeSource *>(this); 438 TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", 439 fTimeSourceThis); 440 if (fTimeSourceThis && fTimeSourceThis->BTimeSource::HandleMessage( 441 message, data, size) == B_OK) { 442 return B_OK; 443 } 444 } 445 446 TRACE("BMediaNode::WaitForMessage calling default HandleMessage\n"); 447 if (B_OK == HandleMessage(message, data, size)) 448 return B_OK; 449 450 HandleBadMessage(message, data, size); 451 452 return B_ERROR; 453 } 454 455 456 /* virtual */ void 457 BMediaNode::Start(bigtime_t performance_time) 458 { 459 CALLED(); 460 // This hook function is called when a node is started 461 // by a call to the BMediaRoster. The specified 462 // performanceTime, the time at which the node 463 // should start running, may be in the future. 464 // It may be overriden by derived classes. 465 // The BMediaEventLooper class handles this event! 466 // The BMediaNode class does nothing here. 467 } 468 469 470 /* virtual */ void 471 BMediaNode::Stop(bigtime_t performance_time, 472 bool immediate) 473 { 474 CALLED(); 475 // This hook function is called when a node is stopped 476 // by a call to the BMediaRoster. The specified 477 // performanceTime, the time at which the node 478 // should stop running, may be in the future. 479 // It may be overriden by derived classes. 480 // The BMediaEventLooper class handles this event! 481 // The BMediaNode class does nothing here. 482 } 483 484 485 /* virtual */ void 486 BMediaNode::Seek(bigtime_t media_time, 487 bigtime_t performance_time) 488 { 489 CALLED(); 490 // This hook function is called when a node is asked 491 // to seek to the specified mediaTime by a call to 492 // the BMediaRoster. The specified performanceTime, 493 // the time at which the node should begin the seek 494 // operation, may be in the future. 495 // It may be overriden by derived classes. 496 // The BMediaEventLooper class handles this event! 497 // The BMediaNode class does nothing here. 498 } 499 500 501 /* virtual */ void 502 BMediaNode::SetRunMode(run_mode mode) 503 { 504 CALLED(); 505 506 // this is a hook function, and 507 // may be overriden by derived classes. 508 509 // the functionality here is only to 510 // support those people that don't 511 // use the roster to set the run mode 512 fRunMode = mode; 513 } 514 515 516 /* virtual */ void 517 BMediaNode::TimeWarp(bigtime_t at_real_time, 518 bigtime_t to_performance_time) 519 { 520 CALLED(); 521 // May be overriden by derived classes. 522 } 523 524 525 /* virtual */ void 526 BMediaNode::Preroll() 527 { 528 CALLED(); 529 // May be overriden by derived classes. 530 } 531 532 533 /* virtual */ void 534 BMediaNode::SetTimeSource(BTimeSource *time_source) 535 { 536 CALLED(); 537 // this is a hook function, and 538 // may be overriden by derived classes. 539 540 if (time_source == NULL || time_source == fTimeSource) 541 return; 542 543 // we just trip into debugger, code that tries to do this is broken. 544 debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, use BMediaRoster::SetTimeSourceFor()!\n"); 545 } 546 547 /************************************************************* 548 * public BMediaNode 549 *************************************************************/ 550 551 /* virtual */ status_t 552 BMediaNode::HandleMessage(int32 message, 553 const void *data, 554 size_t size) 555 { 556 TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID); 557 switch (message) { 558 case NODE_FINAL_RELEASE: 559 { 560 // const node_final_release_command *command = static_cast<const node_final_release_command *>(data); 561 // This is called by the media server to delete the object 562 // after is has been released by all nodes that are using it. 563 // We forward the function to the BMediaRoster, since the 564 // deletion must be done from a different thread, or the 565 // outermost destructor that will exit the thread that is 566 // reading messages from the port (this thread contex) will 567 // quit, and ~BMediaNode destructor won't be called ever. 568 569 TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", this); 570 BMessage msg(NODE_FINAL_RELEASE); 571 msg.AddPointer("node", this); 572 BMediaRoster::Roster()->PostMessage(&msg); 573 574 return B_OK; 575 } 576 577 case NODE_START: 578 { 579 const node_start_command *command = static_cast<const node_start_command *>(data); 580 TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID); 581 Start(command->performance_time); 582 return B_OK; 583 } 584 585 case NODE_STOP: 586 { 587 const node_stop_command *command = static_cast<const node_stop_command *>(data); 588 TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID); 589 Stop(command->performance_time, command->immediate); 590 return B_OK; 591 } 592 593 case NODE_SEEK: 594 { 595 const node_seek_command *command = static_cast<const node_seek_command *>(data); 596 TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID); 597 Seek(command->media_time, command->performance_time); 598 return B_OK; 599 } 600 601 case NODE_SET_RUN_MODE: 602 { 603 const node_set_run_mode_command *command = static_cast<const node_set_run_mode_command *>(data); 604 TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE, node %ld\n", fNodeID); 605 // when changing this, also change PRODUCER_SET_RUN_MODE_DELAY 606 fRunMode = command->mode; 607 SetRunMode(fRunMode); 608 return B_OK; 609 } 610 611 case NODE_TIME_WARP: 612 { 613 const node_time_warp_command *command = static_cast<const node_time_warp_command *>(data); 614 TRACE("BMediaNode::HandleMessage NODE_TIME_WARP, node %ld\n", fNodeID); 615 TimeWarp(command->at_real_time, command->to_performance_time); 616 return B_OK; 617 } 618 619 case NODE_PREROLL: 620 { 621 TRACE("BMediaNode::HandleMessage NODE_PREROLL, node %ld\n", fNodeID); 622 Preroll(); 623 return B_OK; 624 } 625 626 case NODE_SET_TIMESOURCE: 627 { 628 const node_set_timesource_command *command = static_cast<const node_set_timesource_command *>(data); 629 630 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id); 631 632 fTimeSourceID = command->timesource_id; 633 634 if (fTimeSource) { 635 // as this node already had a timesource, we need 636 // we need to remove this node from time source control 637 fTimeSource->RemoveMe(this); 638 // Then release the time source 639 fTimeSource->Release(); 640 // force next call to TimeSource() to create a new object 641 fTimeSource = 0; 642 } 643 644 // create new time source object 645 fTimeSource = TimeSource(); 646 // and call the SetTimeSource hook function to notify 647 // any derived class 648 SetTimeSource(fTimeSource); 649 650 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id); 651 652 return B_OK; 653 } 654 655 case NODE_GET_TIMESOURCE: 656 { 657 const node_get_timesource_request *request = static_cast<const node_get_timesource_request *>(data); 658 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE, node %ld\n", fNodeID); 659 node_get_timesource_reply reply; 660 reply.timesource_id = fTimeSourceID; 661 request->SendReply(B_OK, &reply, sizeof(reply)); 662 return B_OK; 663 } 664 665 case NODE_REQUEST_COMPLETED: 666 { 667 const node_request_completed_command *command = static_cast<const node_request_completed_command *>(data); 668 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED, node %ld\n", fNodeID); 669 RequestCompleted(command->info); 670 return B_OK; 671 } 672 673 }; 674 return B_ERROR; 675 } 676 677 678 void 679 BMediaNode::HandleBadMessage(int32 code, 680 const void *buffer, 681 size_t size) 682 { 683 CALLED(); 684 685 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size); 686 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 687 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 688 } else { 689 /* All messages targeted to nodes should be handled here, 690 * messages targetted to the wrong node should be handled 691 * by returning an error, not by stalling the sender. 692 */ 693 const request_data *request = static_cast<const request_data *>(buffer); 694 reply_data reply; 695 request->SendReply(B_ERROR, &reply, sizeof(reply)); 696 } 697 } 698 699 700 void 701 BMediaNode::AddNodeKind(uint64 kind) 702 { 703 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 704 705 fKinds |= kind; 706 } 707 708 709 void * 710 BMediaNode::operator new(size_t size) 711 { 712 CALLED(); 713 return ::operator new(size); 714 } 715 716 void * 717 BMediaNode::operator new(size_t size, 718 const nothrow_t &) throw() 719 { 720 CALLED(); 721 return ::operator new(size, nothrow); 722 } 723 724 void 725 BMediaNode::operator delete(void *ptr) 726 { 727 CALLED(); 728 ::operator delete(ptr); 729 } 730 731 void 732 BMediaNode::operator delete(void * ptr, 733 const nothrow_t &) throw() 734 { 735 CALLED(); 736 ::operator delete(ptr, nothrow); 737 } 738 739 /************************************************************* 740 * protected BMediaNode 741 *************************************************************/ 742 743 /* virtual */ status_t 744 BMediaNode::RequestCompleted(const media_request_info &info) 745 { 746 CALLED(); 747 // This function is called whenever a request issued by the node is completed. 748 // May be overriden by derived classes. 749 // info.change_tag can be used to match up requests against 750 // the accompaning calles from 751 // BBufferConsumer::RequestFormatChange() 752 // BBufferConsumer::SetOutputBuffersFor() 753 // BBufferConsumer::SetOutputEnabled() 754 // BBufferConsumer::SetVideoClippingFor() 755 return B_OK; 756 } 757 758 /************************************************************* 759 * private BMediaNode 760 *************************************************************/ 761 762 int32 763 BMediaNode::IncrementChangeTag() 764 { 765 CALLED(); 766 // Only present in BeOS R4 767 // Obsoleted in BeOS R4.5 and later 768 // "updates the change tag, so that downstream consumers know that the node is in a new state." 769 // not supported, only for binary compatibility 770 return 0; 771 } 772 773 774 int32 775 BMediaNode::ChangeTag() 776 { 777 UNIMPLEMENTED(); 778 // Only present in BeOS R4 779 // Obsoleted in BeOS R4.5 and later 780 // "returns the node's current change tag value." 781 // not supported, only for binary compatibility 782 return 0; 783 } 784 785 786 int32 787 BMediaNode::MintChangeTag() 788 { 789 UNIMPLEMENTED(); 790 // Only present in BeOS R4 791 // Obsoleted in BeOS R4.5 and later 792 // "mints a new, reserved, change tag." 793 // "Call ApplyChangeTag() to apply it to the node" 794 // not supported, only for binary compatibility 795 return 0; 796 } 797 798 799 status_t 800 BMediaNode::ApplyChangeTag(int32 previously_reserved) 801 { 802 UNIMPLEMENTED(); 803 // Only present in BeOS R4 804 // Obsoleted in BeOS R4.5 and later 805 // "this returns B_OK if the new change tag is" 806 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 807 // "count you tried to apply is already obsolete." 808 // not supported, only for binary compatibility 809 return B_OK; 810 } 811 812 /************************************************************* 813 * protected BMediaNode 814 *************************************************************/ 815 816 /* virtual */ status_t 817 BMediaNode::DeleteHook(BMediaNode *node) 818 { 819 CALLED(); 820 delete this; // delete "this" or "node", both are the same 821 return B_OK; 822 } 823 824 825 /* virtual */ void 826 BMediaNode::NodeRegistered() 827 { 828 CALLED(); 829 // The Media Server calls this hook function after the node has been registered. 830 // May be overriden by derived classes. 831 } 832 833 /************************************************************* 834 * public BMediaNode 835 *************************************************************/ 836 837 /* virtual */ status_t 838 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes, 839 size_t inMaxCount) 840 { 841 UNIMPLEMENTED(); 842 843 return B_ERROR; 844 } 845 846 847 /* virtual */ status_t 848 BMediaNode::AddTimer(bigtime_t at_performance_time, 849 int32 cookie) 850 { 851 UNIMPLEMENTED(); 852 853 return B_ERROR; 854 } 855 856 857 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; } 858 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; } 859 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; } 860 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; } 861 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; } 862 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; } 863 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; } 864 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; } 865 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; } 866 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; } 867 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; } 868 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; } 869 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; } 870 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; } 871 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; } 872 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; } 873 874 /* 875 private unimplemented 876 BMediaNode::BMediaNode() 877 BMediaNode::BMediaNode(const BMediaNode &clone) 878 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 879 */ 880 881 void 882 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) 883 { 884 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 885 886 fNodeID = id; 887 fRefCount = 1; 888 fName[0] = 0; 889 if (name) { 890 strncpy(fName, name, B_MEDIA_NAME_LENGTH - 1); 891 fName[B_MEDIA_NAME_LENGTH - 1] = 0; 892 } 893 fRunMode = B_INCREASE_LATENCY; 894 fKinds = kinds; 895 fProducerThis = 0; 896 fConsumerThis = 0; 897 fFileInterfaceThis = 0; 898 fControllableThis = 0; 899 fTimeSourceThis = 0; 900 901 // create control port 902 fControlPort = create_port(64, fName); 903 904 // nodes are assigned the system time source by default 905 fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; 906 907 // We can't create the timesource object here, because 908 // every timesource is a BMediaNode, which would result 909 // in infinite recursions 910 fTimeSource = NULL; 911 } 912 913 914 BMediaNode::BMediaNode(const char *name, 915 media_node_id id, 916 uint32 kinds) 917 { 918 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds); 919 _InitObject(name, id, kinds); 920 } 921 922 923 /************************************************************* 924 * protected BMediaNode 925 *************************************************************/ 926 927 /* static */ int32 928 BMediaNode::NewChangeTag() 929 { 930 CALLED(); 931 // change tags have been used in BeOS R4 to match up 932 // format change requests between producer and consumer, 933 // This has changed starting with R4.5 934 // now "change tags" are used with 935 // BMediaNode::RequestCompleted() 936 // and 937 // BBufferConsumer::RequestFormatChange() 938 // BBufferConsumer::SetOutputBuffersFor() 939 // BBufferConsumer::SetOutputEnabled() 940 // BBufferConsumer::SetVideoClippingFor() 941 return atomic_add(&BMediaNode::_m_changeTag,1); 942 } 943