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 == GENERAL_PURPOSE_WAKEUP) return B_OK; // no action needed 381 382 if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { 383 TRACE("BMediaNode::WaitForMessage calling BMediaNode\n"); 384 if (B_OK == BMediaNode::HandleMessage(message, data, size)) 385 return B_OK; 386 } 387 388 if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) { 389 if (!fProducerThis) 390 fProducerThis = dynamic_cast<BBufferProducer *>(this); 391 TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", 392 fProducerThis); 393 if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage( 394 message, data, size) == B_OK) { 395 return B_OK; 396 } 397 } 398 399 if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) { 400 if (!fConsumerThis) 401 fConsumerThis = dynamic_cast<BBufferConsumer *>(this); 402 TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", 403 fConsumerThis); 404 if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage( 405 message, data, size) == B_OK) { 406 return B_OK; 407 } 408 } 409 410 if (message > FILEINTERFACE_MESSAGE_START 411 && message < FILEINTERFACE_MESSAGE_END) { 412 if (!fFileInterfaceThis) 413 fFileInterfaceThis = dynamic_cast<BFileInterface *>(this); 414 TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", 415 fFileInterfaceThis); 416 if (fFileInterfaceThis 417 && fFileInterfaceThis->BFileInterface::HandleMessage( 418 message, data, size) == B_OK) { 419 return B_OK; 420 } 421 } 422 423 if (message > CONTROLLABLE_MESSAGE_START 424 && message < CONTROLLABLE_MESSAGE_END) { 425 if (!fControllableThis) 426 fControllableThis = dynamic_cast<BControllable *>(this); 427 TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", 428 fControllableThis); 429 if (fControllableThis 430 && fControllableThis->BControllable::HandleMessage( 431 message, data, size) == B_OK) { 432 return B_OK; 433 } 434 } 435 436 if (message > TIMESOURCE_MESSAGE_START 437 && message < TIMESOURCE_MESSAGE_END) { 438 if (!fTimeSourceThis) 439 fTimeSourceThis = dynamic_cast<BTimeSource *>(this); 440 TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", 441 fTimeSourceThis); 442 if (fTimeSourceThis && fTimeSourceThis->BTimeSource::HandleMessage( 443 message, data, size) == B_OK) { 444 return B_OK; 445 } 446 } 447 448 TRACE("BMediaNode::WaitForMessage calling default HandleMessage\n"); 449 if (B_OK == HandleMessage(message, data, size)) 450 return B_OK; 451 452 HandleBadMessage(message, data, size); 453 454 return B_ERROR; 455 } 456 457 458 /* virtual */ void 459 BMediaNode::Start(bigtime_t performance_time) 460 { 461 CALLED(); 462 // This hook function is called when a node is started 463 // by a call to the BMediaRoster. The specified 464 // performanceTime, the time at which the node 465 // should start running, may be in the future. 466 // It may be overriden by derived classes. 467 // The BMediaEventLooper class handles this event! 468 // The BMediaNode class does nothing here. 469 } 470 471 472 /* virtual */ void 473 BMediaNode::Stop(bigtime_t performance_time, 474 bool immediate) 475 { 476 CALLED(); 477 // This hook function is called when a node is stopped 478 // by a call to the BMediaRoster. The specified 479 // performanceTime, the time at which the node 480 // should stop running, may be in the future. 481 // It may be overriden by derived classes. 482 // The BMediaEventLooper class handles this event! 483 // The BMediaNode class does nothing here. 484 } 485 486 487 /* virtual */ void 488 BMediaNode::Seek(bigtime_t media_time, 489 bigtime_t performance_time) 490 { 491 CALLED(); 492 // This hook function is called when a node is asked 493 // to seek to the specified mediaTime by a call to 494 // the BMediaRoster. The specified performanceTime, 495 // the time at which the node should begin the seek 496 // operation, may be in the future. 497 // It may be overriden by derived classes. 498 // The BMediaEventLooper class handles this event! 499 // The BMediaNode class does nothing here. 500 } 501 502 503 /* virtual */ void 504 BMediaNode::SetRunMode(run_mode mode) 505 { 506 CALLED(); 507 508 // this is a hook function, and 509 // may be overriden by derived classes. 510 511 // the functionality here is only to 512 // support those people that don't 513 // use the roster to set the run mode 514 fRunMode = mode; 515 } 516 517 518 /* virtual */ void 519 BMediaNode::TimeWarp(bigtime_t at_real_time, 520 bigtime_t to_performance_time) 521 { 522 CALLED(); 523 // May be overriden by derived classes. 524 } 525 526 527 /* virtual */ void 528 BMediaNode::Preroll() 529 { 530 CALLED(); 531 // May be overriden by derived classes. 532 } 533 534 535 /* virtual */ void 536 BMediaNode::SetTimeSource(BTimeSource *time_source) 537 { 538 CALLED(); 539 // this is a hook function, and 540 // may be overriden by derived classes. 541 542 if (time_source == NULL || time_source == fTimeSource) 543 return; 544 545 // we just trip into debugger, code that tries to do this is broken. 546 debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, use BMediaRoster::SetTimeSourceFor()!\n"); 547 } 548 549 /************************************************************* 550 * public BMediaNode 551 *************************************************************/ 552 553 /* virtual */ status_t 554 BMediaNode::HandleMessage(int32 message, 555 const void *data, 556 size_t size) 557 { 558 TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID); 559 switch (message) { 560 case NODE_FINAL_RELEASE: 561 { 562 // const node_final_release_command *command = static_cast<const node_final_release_command *>(data); 563 // This is called by the media server to delete the object 564 // after is has been released by all nodes that are using it. 565 // We forward the function to the BMediaRoster, since the 566 // deletion must be done from a different thread, or the 567 // outermost destructor that will exit the thread that is 568 // reading messages from the port (this thread contex) will 569 // quit, and ~BMediaNode destructor won't be called ever. 570 571 TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", this); 572 BMessage msg(NODE_FINAL_RELEASE); 573 msg.AddPointer("node", this); 574 BMediaRoster::Roster()->PostMessage(&msg); 575 576 return B_OK; 577 } 578 579 case NODE_START: 580 { 581 const node_start_command *command = static_cast<const node_start_command *>(data); 582 TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID); 583 Start(command->performance_time); 584 return B_OK; 585 } 586 587 case NODE_STOP: 588 { 589 const node_stop_command *command = static_cast<const node_stop_command *>(data); 590 TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID); 591 Stop(command->performance_time, command->immediate); 592 return B_OK; 593 } 594 595 case NODE_SEEK: 596 { 597 const node_seek_command *command = static_cast<const node_seek_command *>(data); 598 TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID); 599 Seek(command->media_time, command->performance_time); 600 return B_OK; 601 } 602 603 case NODE_SET_RUN_MODE: 604 { 605 const node_set_run_mode_command *command = static_cast<const node_set_run_mode_command *>(data); 606 TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE, node %ld\n", fNodeID); 607 // when changing this, also change PRODUCER_SET_RUN_MODE_DELAY 608 fRunMode = command->mode; 609 SetRunMode(fRunMode); 610 return B_OK; 611 } 612 613 case NODE_TIME_WARP: 614 { 615 const node_time_warp_command *command = static_cast<const node_time_warp_command *>(data); 616 TRACE("BMediaNode::HandleMessage NODE_TIME_WARP, node %ld\n", fNodeID); 617 TimeWarp(command->at_real_time, command->to_performance_time); 618 return B_OK; 619 } 620 621 case NODE_PREROLL: 622 { 623 TRACE("BMediaNode::HandleMessage NODE_PREROLL, node %ld\n", fNodeID); 624 Preroll(); 625 return B_OK; 626 } 627 628 case NODE_SET_TIMESOURCE: 629 { 630 const node_set_timesource_command *command = static_cast<const node_set_timesource_command *>(data); 631 632 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id); 633 634 fTimeSourceID = command->timesource_id; 635 636 if (fTimeSource) { 637 // as this node already had a timesource, we need 638 // we need to remove this node from time source control 639 fTimeSource->RemoveMe(this); 640 // Then release the time source 641 fTimeSource->Release(); 642 // force next call to TimeSource() to create a new object 643 fTimeSource = 0; 644 } 645 646 // create new time source object 647 fTimeSource = TimeSource(); 648 // and call the SetTimeSource hook function to notify 649 // any derived class 650 SetTimeSource(fTimeSource); 651 652 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id); 653 654 return B_OK; 655 } 656 657 case NODE_GET_TIMESOURCE: 658 { 659 const node_get_timesource_request *request = static_cast<const node_get_timesource_request *>(data); 660 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE, node %ld\n", fNodeID); 661 node_get_timesource_reply reply; 662 reply.timesource_id = fTimeSourceID; 663 request->SendReply(B_OK, &reply, sizeof(reply)); 664 return B_OK; 665 } 666 667 case NODE_REQUEST_COMPLETED: 668 { 669 const node_request_completed_command *command = static_cast<const node_request_completed_command *>(data); 670 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED, node %ld\n", fNodeID); 671 RequestCompleted(command->info); 672 return B_OK; 673 } 674 675 }; 676 return B_ERROR; 677 } 678 679 680 void 681 BMediaNode::HandleBadMessage(int32 code, 682 const void *buffer, 683 size_t size) 684 { 685 CALLED(); 686 687 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size); 688 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 689 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 690 } else { 691 /* All messages targeted to nodes should be handled here, 692 * messages targetted to the wrong node should be handled 693 * by returning an error, not by stalling the sender. 694 */ 695 const request_data *request = static_cast<const request_data *>(buffer); 696 reply_data reply; 697 request->SendReply(B_ERROR, &reply, sizeof(reply)); 698 } 699 } 700 701 702 void 703 BMediaNode::AddNodeKind(uint64 kind) 704 { 705 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 706 707 fKinds |= kind; 708 } 709 710 711 void * 712 BMediaNode::operator new(size_t size) 713 { 714 CALLED(); 715 return ::operator new(size); 716 } 717 718 void * 719 BMediaNode::operator new(size_t size, 720 const nothrow_t &) throw() 721 { 722 CALLED(); 723 return ::operator new(size, nothrow); 724 } 725 726 void 727 BMediaNode::operator delete(void *ptr) 728 { 729 CALLED(); 730 ::operator delete(ptr); 731 } 732 733 void 734 BMediaNode::operator delete(void * ptr, 735 const nothrow_t &) throw() 736 { 737 CALLED(); 738 ::operator delete(ptr, nothrow); 739 } 740 741 /************************************************************* 742 * protected BMediaNode 743 *************************************************************/ 744 745 /* virtual */ status_t 746 BMediaNode::RequestCompleted(const media_request_info &info) 747 { 748 CALLED(); 749 // This function is called whenever a request issued by the node is completed. 750 // May be overriden by derived classes. 751 // info.change_tag can be used to match up requests against 752 // the accompaning calles from 753 // BBufferConsumer::RequestFormatChange() 754 // BBufferConsumer::SetOutputBuffersFor() 755 // BBufferConsumer::SetOutputEnabled() 756 // BBufferConsumer::SetVideoClippingFor() 757 return B_OK; 758 } 759 760 /************************************************************* 761 * private BMediaNode 762 *************************************************************/ 763 764 int32 765 BMediaNode::IncrementChangeTag() 766 { 767 CALLED(); 768 // Only present in BeOS R4 769 // Obsoleted in BeOS R4.5 and later 770 // "updates the change tag, so that downstream consumers know that the node is in a new state." 771 // not supported, only for binary compatibility 772 return 0; 773 } 774 775 776 int32 777 BMediaNode::ChangeTag() 778 { 779 UNIMPLEMENTED(); 780 // Only present in BeOS R4 781 // Obsoleted in BeOS R4.5 and later 782 // "returns the node's current change tag value." 783 // not supported, only for binary compatibility 784 return 0; 785 } 786 787 788 int32 789 BMediaNode::MintChangeTag() 790 { 791 UNIMPLEMENTED(); 792 // Only present in BeOS R4 793 // Obsoleted in BeOS R4.5 and later 794 // "mints a new, reserved, change tag." 795 // "Call ApplyChangeTag() to apply it to the node" 796 // not supported, only for binary compatibility 797 return 0; 798 } 799 800 801 status_t 802 BMediaNode::ApplyChangeTag(int32 previously_reserved) 803 { 804 UNIMPLEMENTED(); 805 // Only present in BeOS R4 806 // Obsoleted in BeOS R4.5 and later 807 // "this returns B_OK if the new change tag is" 808 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 809 // "count you tried to apply is already obsolete." 810 // not supported, only for binary compatibility 811 return B_OK; 812 } 813 814 /************************************************************* 815 * protected BMediaNode 816 *************************************************************/ 817 818 /* virtual */ status_t 819 BMediaNode::DeleteHook(BMediaNode *node) 820 { 821 CALLED(); 822 delete this; // delete "this" or "node", both are the same 823 return B_OK; 824 } 825 826 827 /* virtual */ void 828 BMediaNode::NodeRegistered() 829 { 830 CALLED(); 831 // The Media Server calls this hook function after the node has been registered. 832 // May be overriden by derived classes. 833 } 834 835 /************************************************************* 836 * public BMediaNode 837 *************************************************************/ 838 839 /* virtual */ status_t 840 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes, 841 size_t inMaxCount) 842 { 843 UNIMPLEMENTED(); 844 845 return B_ERROR; 846 } 847 848 849 /* virtual */ status_t 850 BMediaNode::AddTimer(bigtime_t at_performance_time, 851 int32 cookie) 852 { 853 UNIMPLEMENTED(); 854 855 return B_ERROR; 856 } 857 858 859 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; } 860 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; } 861 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; } 862 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; } 863 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; } 864 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; } 865 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; } 866 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; } 867 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; } 868 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; } 869 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; } 870 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; } 871 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; } 872 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; } 873 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; } 874 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; } 875 876 /* 877 private unimplemented 878 BMediaNode::BMediaNode() 879 BMediaNode::BMediaNode(const BMediaNode &clone) 880 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 881 */ 882 883 void 884 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) 885 { 886 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 887 888 fNodeID = id; 889 fRefCount = 1; 890 fName[0] = 0; 891 if (name) 892 strlcpy(fName, name, B_MEDIA_NAME_LENGTH); 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