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