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 delete their control ports, since they are only a 152 // shadow object, and the real one still exists 153 if (0 == (fKinds & NODE_KIND_SHADOW_TIMESOURCE)) { 154 if (fControlPort > 0) 155 delete_port(fControlPort); 156 } else { 157 TRACE("BMediaNode::~BMediaNode: shadow timesource, not unregistering\n"); 158 } 159 } 160 161 /************************************************************* 162 * public BMediaNode 163 *************************************************************/ 164 165 BMediaNode * 166 BMediaNode::Acquire() 167 { 168 CALLED(); 169 atomic_add(&fRefCount,1); 170 return this; 171 } 172 173 174 BMediaNode * 175 BMediaNode::Release() 176 { 177 CALLED(); 178 if (atomic_add(&fRefCount, -1) == 1) { 179 TRACE("BMediaNode::Release() saving node %ld configuration\n", fNodeID); 180 MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(this); 181 if (DeleteHook(this) != B_OK) { 182 ERROR("BMediaNode::Release(): DeleteHook failed\n"); 183 return Acquire(); 184 } 185 return NULL; 186 } 187 return this; 188 } 189 190 191 const char * 192 BMediaNode::Name() const 193 { 194 CALLED(); 195 return fName; 196 } 197 198 199 media_node_id 200 BMediaNode::ID() const 201 { 202 CALLED(); 203 return fNodeID; 204 } 205 206 207 uint64 208 BMediaNode::Kinds() const 209 { 210 CALLED(); 211 return fKinds & NODE_KIND_USER_MASK; 212 } 213 214 215 media_node 216 BMediaNode::Node() const 217 { 218 CALLED(); 219 media_node temp; 220 temp.node = ID(); 221 temp.port = ControlPort(); // we *must* call ControlPort(), some derived nodes use it to start the port read thread! 222 temp.kind = Kinds(); 223 return temp; 224 } 225 226 227 BMediaNode::run_mode 228 BMediaNode::RunMode() const 229 { 230 CALLED(); 231 return fRunMode; 232 } 233 234 235 BTimeSource * 236 BMediaNode::TimeSource() const 237 { 238 PRINT(7, "CALLED BMediaNode::TimeSource()\n"); 239 240 // return the currently assigned time source 241 if (fTimeSource != 0) 242 return fTimeSource; 243 244 TRACE("BMediaNode::TimeSource node %ld enter\n", ID()); 245 246 // If the node doesn't have a time source object, we need to create one. 247 // If the node is still unregistered, we can't call MakeTimeSourceFor(), 248 // but since the node does still have the default system time source, we 249 // can use GetSystemTimeSource 250 251 BMediaNode *self = const_cast<BMediaNode *>(this); 252 // if (fTimeSourceID == NODE_SYSTEM_TIMESOURCE_ID) { 253 // self->fTimeSource = _TimeSourceObjectManager->GetSystemTimeSource(); 254 // } else { 255 self->fTimeSource = MediaRosterEx(BMediaRoster::Roster())->MakeTimeSourceObject(fTimeSourceID); 256 // } 257 ASSERT(fTimeSource == self->fTimeSource); 258 259 if (fTimeSource == 0) { 260 ERROR("BMediaNode::TimeSource: MakeTimeSourceFor failed\n"); 261 } else { 262 ASSERT(fTimeSourceID == fTimeSource->ID()); 263 fTimeSource->AddMe(self); 264 } 265 266 TRACE("BMediaNode::TimeSource node %ld leave\n", ID()); 267 268 return fTimeSource; 269 } 270 271 272 /* virtual */ port_id 273 BMediaNode::ControlPort() const 274 { 275 PRINT(7, "CALLED BMediaNode::ControlPort()\n"); 276 return fControlPort; 277 } 278 279 280 /************************************************************* 281 * protected BMediaNode 282 *************************************************************/ 283 284 status_t 285 BMediaNode::ReportError(node_error what, 286 const BMessage *info) 287 { 288 CALLED(); 289 290 // sanity check the what value 291 switch (what) { 292 case BMediaNode::B_NODE_FAILED_START: 293 case BMediaNode::B_NODE_FAILED_STOP: 294 case BMediaNode::B_NODE_FAILED_SEEK: 295 case BMediaNode::B_NODE_FAILED_SET_RUN_MODE: 296 case BMediaNode::B_NODE_FAILED_TIME_WARP: 297 case BMediaNode::B_NODE_FAILED_PREROLL: 298 case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR: 299 case BMediaNode::B_NODE_IN_DISTRESS: 300 break; 301 default: 302 ERROR("BMediaNode::ReportError: invalid what!\n"); 303 return B_BAD_VALUE; 304 } 305 306 // Transmits the error code specified by what to anyone 307 // that's receiving notifications from this node 308 return BPrivate::media::notifications::ReportError(Node(), what, info); 309 } 310 311 312 status_t 313 BMediaNode::NodeStopped(bigtime_t whenPerformance) 314 { 315 UNIMPLEMENTED(); 316 // called by derived classes when they have 317 // finished handling a stop request. 318 319 // notify anyone who is listening for stop notifications! 320 BPrivate::media::notifications::NodeStopped(Node(), whenPerformance); 321 322 // XXX If your node is a BBufferProducer, downstream consumers 323 // XXX will be notified that your node stopped (automatically, no less) 324 // XXX through the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call. 325 326 return B_OK; 327 } 328 329 330 void 331 BMediaNode::TimerExpired(bigtime_t notifyPoint, 332 int32 cookie, 333 status_t error) 334 { 335 UNIMPLEMENTED(); 336 // Used with AddTimer 337 // This will, in turn, cause the BMediaRoster::SyncToNode() call 338 // that instigated the timer to return to the caller. 339 // Probably only important to classes derived from BTimeSource. 340 } 341 342 343 /* explicit */ 344 BMediaNode::BMediaNode(const char *name) 345 { 346 TRACE("BMediaNode::BMediaNode: name '%s'\n", name); 347 _InitObject(name, NODE_JUST_CREATED_ID, 0); 348 } 349 350 351 status_t 352 BMediaNode::WaitForMessage(bigtime_t waitUntil, 353 uint32 flags, 354 void *_reserved_) 355 { 356 TRACE("entering: BMediaNode::WaitForMessage()\n"); 357 358 // This function waits until either real time specified by 359 // waitUntil or a message is received on the control port. 360 // The flags are currently unused and should be 0. 361 362 char data[B_MEDIA_MESSAGE_SIZE]; // about 16 KByte stack used 363 int32 message; 364 ssize_t size; 365 while (true) { 366 size = read_port_etc(ControlPort(), &message, data, 367 sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil); 368 369 if (size >= 0) 370 break; 371 372 status_t error = (status_t)size; 373 if (error == B_INTERRUPTED) 374 continue; 375 376 if (error != B_TIMED_OUT && error != B_BAD_PORT_ID) { 377 ERROR("BMediaNode::WaitForMessage: read_port_etc error: %s\n", 378 strerror(error)); 379 } 380 381 return error; 382 } 383 384 TRACE("BMediaNode::WaitForMessage request is: %#lx, node %ld, this %p\n", 385 message, fNodeID, this); 386 387 if (message == GENERAL_PURPOSE_WAKEUP) return B_OK; // no action needed 388 389 if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { 390 TRACE("BMediaNode::WaitForMessage calling BMediaNode\n"); 391 if (B_OK == BMediaNode::HandleMessage(message, data, size)) 392 return B_OK; 393 } 394 395 if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) { 396 if (!fProducerThis) 397 fProducerThis = dynamic_cast<BBufferProducer *>(this); 398 TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", 399 fProducerThis); 400 if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage( 401 message, data, size) == B_OK) { 402 return B_OK; 403 } 404 } 405 406 if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) { 407 if (!fConsumerThis) 408 fConsumerThis = dynamic_cast<BBufferConsumer *>(this); 409 TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", 410 fConsumerThis); 411 if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage( 412 message, data, size) == B_OK) { 413 return B_OK; 414 } 415 } 416 417 if (message > FILEINTERFACE_MESSAGE_START 418 && message < FILEINTERFACE_MESSAGE_END) { 419 if (!fFileInterfaceThis) 420 fFileInterfaceThis = dynamic_cast<BFileInterface *>(this); 421 TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", 422 fFileInterfaceThis); 423 if (fFileInterfaceThis 424 && fFileInterfaceThis->BFileInterface::HandleMessage( 425 message, data, size) == B_OK) { 426 return B_OK; 427 } 428 } 429 430 if (message > CONTROLLABLE_MESSAGE_START 431 && message < CONTROLLABLE_MESSAGE_END) { 432 if (!fControllableThis) 433 fControllableThis = dynamic_cast<BControllable *>(this); 434 TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", 435 fControllableThis); 436 if (fControllableThis 437 && fControllableThis->BControllable::HandleMessage( 438 message, data, size) == B_OK) { 439 return B_OK; 440 } 441 } 442 443 if (message > TIMESOURCE_MESSAGE_START 444 && message < TIMESOURCE_MESSAGE_END) { 445 if (!fTimeSourceThis) 446 fTimeSourceThis = dynamic_cast<BTimeSource *>(this); 447 TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", 448 fTimeSourceThis); 449 if (fTimeSourceThis && fTimeSourceThis->BTimeSource::HandleMessage( 450 message, data, size) == B_OK) { 451 return B_OK; 452 } 453 } 454 455 TRACE("BMediaNode::WaitForMessage calling default HandleMessage\n"); 456 if (B_OK == HandleMessage(message, data, size)) 457 return B_OK; 458 459 HandleBadMessage(message, data, size); 460 461 return B_ERROR; 462 } 463 464 465 /* virtual */ void 466 BMediaNode::Start(bigtime_t performance_time) 467 { 468 CALLED(); 469 // This hook function is called when a node is started 470 // by a call to the BMediaRoster. The specified 471 // performanceTime, the time at which the node 472 // should start running, 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::Stop(bigtime_t performance_time, 481 bool immediate) 482 { 483 CALLED(); 484 // This hook function is called when a node is stopped 485 // by a call to the BMediaRoster. The specified 486 // performanceTime, the time at which the node 487 // should stop running, may be in the future. 488 // It may be overriden by derived classes. 489 // The BMediaEventLooper class handles this event! 490 // The BMediaNode class does nothing here. 491 } 492 493 494 /* virtual */ void 495 BMediaNode::Seek(bigtime_t media_time, 496 bigtime_t performance_time) 497 { 498 CALLED(); 499 // This hook function is called when a node is asked 500 // to seek to the specified mediaTime by a call to 501 // the BMediaRoster. The specified performanceTime, 502 // the time at which the node should begin the seek 503 // operation, may be in the future. 504 // It may be overriden by derived classes. 505 // The BMediaEventLooper class handles this event! 506 // The BMediaNode class does nothing here. 507 } 508 509 510 /* virtual */ void 511 BMediaNode::SetRunMode(run_mode mode) 512 { 513 CALLED(); 514 515 // this is a hook function, and 516 // may be overriden by derived classes. 517 518 // the functionality here is only to 519 // support those people that don't 520 // use the roster to set the run mode 521 fRunMode = mode; 522 } 523 524 525 /* virtual */ void 526 BMediaNode::TimeWarp(bigtime_t at_real_time, 527 bigtime_t to_performance_time) 528 { 529 CALLED(); 530 // May be overriden by derived classes. 531 } 532 533 534 /* virtual */ void 535 BMediaNode::Preroll() 536 { 537 CALLED(); 538 // May be overriden by derived classes. 539 } 540 541 542 /* virtual */ void 543 BMediaNode::SetTimeSource(BTimeSource *time_source) 544 { 545 CALLED(); 546 // this is a hook function, and 547 // may be overriden by derived classes. 548 549 if (time_source == NULL || time_source == fTimeSource) 550 return; 551 552 // we just trip into debugger, code that tries to do this is broken. 553 debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, use BMediaRoster::SetTimeSourceFor()!\n"); 554 } 555 556 /************************************************************* 557 * public BMediaNode 558 *************************************************************/ 559 560 /* virtual */ status_t 561 BMediaNode::HandleMessage(int32 message, 562 const void *data, 563 size_t size) 564 { 565 TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID); 566 switch (message) { 567 case NODE_FINAL_RELEASE: 568 { 569 // const node_final_release_command *command = static_cast<const node_final_release_command *>(data); 570 // This is called by the media server to delete the object 571 // after is has been released by all nodes that are using it. 572 // We forward the function to the BMediaRoster, since the 573 // deletion must be done from a different thread, or the 574 // outermost destructor that will exit the thread that is 575 // reading messages from the port (this thread contex) will 576 // quit, and ~BMediaNode destructor won't be called ever. 577 578 TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", this); 579 BMessage msg(NODE_FINAL_RELEASE); 580 msg.AddPointer("node", this); 581 BMediaRoster::Roster()->PostMessage(&msg); 582 583 return B_OK; 584 } 585 586 case NODE_START: 587 { 588 const node_start_command *command = static_cast<const node_start_command *>(data); 589 TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID); 590 Start(command->performance_time); 591 return B_OK; 592 } 593 594 case NODE_STOP: 595 { 596 const node_stop_command *command = static_cast<const node_stop_command *>(data); 597 TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID); 598 Stop(command->performance_time, command->immediate); 599 return B_OK; 600 } 601 602 case NODE_SEEK: 603 { 604 const node_seek_command *command = static_cast<const node_seek_command *>(data); 605 TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID); 606 Seek(command->media_time, command->performance_time); 607 return B_OK; 608 } 609 610 case NODE_SET_RUN_MODE: 611 { 612 const node_set_run_mode_command *command = static_cast<const node_set_run_mode_command *>(data); 613 TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE, node %ld\n", fNodeID); 614 // when changing this, also change PRODUCER_SET_RUN_MODE_DELAY 615 fRunMode = command->mode; 616 SetRunMode(fRunMode); 617 return B_OK; 618 } 619 620 case NODE_TIME_WARP: 621 { 622 const node_time_warp_command *command = static_cast<const node_time_warp_command *>(data); 623 TRACE("BMediaNode::HandleMessage NODE_TIME_WARP, node %ld\n", fNodeID); 624 TimeWarp(command->at_real_time, command->to_performance_time); 625 return B_OK; 626 } 627 628 case NODE_PREROLL: 629 { 630 TRACE("BMediaNode::HandleMessage NODE_PREROLL, node %ld\n", fNodeID); 631 Preroll(); 632 return B_OK; 633 } 634 635 case NODE_SET_TIMESOURCE: 636 { 637 const node_set_timesource_command *command = static_cast<const node_set_timesource_command *>(data); 638 639 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id); 640 641 fTimeSourceID = command->timesource_id; 642 643 if (fTimeSource) { 644 // as this node already had a timesource, we need 645 // we need to remove this node from time source control 646 fTimeSource->RemoveMe(this); 647 // Then release the time source 648 fTimeSource->Release(); 649 // force next call to TimeSource() to create a new object 650 fTimeSource = 0; 651 } 652 653 // create new time source object 654 fTimeSource = TimeSource(); 655 // and call the SetTimeSource hook function to notify 656 // any derived class 657 SetTimeSource(fTimeSource); 658 659 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id); 660 661 return B_OK; 662 } 663 664 case NODE_GET_TIMESOURCE: 665 { 666 const node_get_timesource_request *request = static_cast<const node_get_timesource_request *>(data); 667 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE, node %ld\n", fNodeID); 668 node_get_timesource_reply reply; 669 reply.timesource_id = fTimeSourceID; 670 request->SendReply(B_OK, &reply, sizeof(reply)); 671 return B_OK; 672 } 673 674 case NODE_REQUEST_COMPLETED: 675 { 676 const node_request_completed_command *command = static_cast<const node_request_completed_command *>(data); 677 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED, node %ld\n", fNodeID); 678 RequestCompleted(command->info); 679 return B_OK; 680 } 681 682 }; 683 return B_ERROR; 684 } 685 686 687 void 688 BMediaNode::HandleBadMessage(int32 code, 689 const void *buffer, 690 size_t size) 691 { 692 CALLED(); 693 694 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size); 695 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 696 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 697 } else { 698 /* All messages targeted to nodes should be handled here, 699 * messages targetted to the wrong node should be handled 700 * by returning an error, not by stalling the sender. 701 */ 702 const request_data *request = static_cast<const request_data *>(buffer); 703 reply_data reply; 704 request->SendReply(B_ERROR, &reply, sizeof(reply)); 705 } 706 } 707 708 709 void 710 BMediaNode::AddNodeKind(uint64 kind) 711 { 712 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 713 714 fKinds |= kind; 715 } 716 717 718 void * 719 BMediaNode::operator new(size_t size) 720 { 721 CALLED(); 722 return ::operator new(size); 723 } 724 725 void * 726 BMediaNode::operator new(size_t size, 727 const nothrow_t &) throw() 728 { 729 CALLED(); 730 return ::operator new(size, nothrow); 731 } 732 733 void 734 BMediaNode::operator delete(void *ptr) 735 { 736 CALLED(); 737 ::operator delete(ptr); 738 } 739 740 void 741 BMediaNode::operator delete(void * ptr, 742 const nothrow_t &) throw() 743 { 744 CALLED(); 745 ::operator delete(ptr, nothrow); 746 } 747 748 /************************************************************* 749 * protected BMediaNode 750 *************************************************************/ 751 752 /* virtual */ status_t 753 BMediaNode::RequestCompleted(const media_request_info &info) 754 { 755 CALLED(); 756 // This function is called whenever a request issued by the node is completed. 757 // May be overriden by derived classes. 758 // info.change_tag can be used to match up requests against 759 // the accompaning calles from 760 // BBufferConsumer::RequestFormatChange() 761 // BBufferConsumer::SetOutputBuffersFor() 762 // BBufferConsumer::SetOutputEnabled() 763 // BBufferConsumer::SetVideoClippingFor() 764 return B_OK; 765 } 766 767 /************************************************************* 768 * private BMediaNode 769 *************************************************************/ 770 771 int32 772 BMediaNode::IncrementChangeTag() 773 { 774 CALLED(); 775 // Only present in BeOS R4 776 // Obsoleted in BeOS R4.5 and later 777 // "updates the change tag, so that downstream consumers know that the node is in a new state." 778 // not supported, only for binary compatibility 779 return 0; 780 } 781 782 783 int32 784 BMediaNode::ChangeTag() 785 { 786 UNIMPLEMENTED(); 787 // Only present in BeOS R4 788 // Obsoleted in BeOS R4.5 and later 789 // "returns the node's current change tag value." 790 // not supported, only for binary compatibility 791 return 0; 792 } 793 794 795 int32 796 BMediaNode::MintChangeTag() 797 { 798 UNIMPLEMENTED(); 799 // Only present in BeOS R4 800 // Obsoleted in BeOS R4.5 and later 801 // "mints a new, reserved, change tag." 802 // "Call ApplyChangeTag() to apply it to the node" 803 // not supported, only for binary compatibility 804 return 0; 805 } 806 807 808 status_t 809 BMediaNode::ApplyChangeTag(int32 previously_reserved) 810 { 811 UNIMPLEMENTED(); 812 // Only present in BeOS R4 813 // Obsoleted in BeOS R4.5 and later 814 // "this returns B_OK if the new change tag is" 815 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 816 // "count you tried to apply is already obsolete." 817 // not supported, only for binary compatibility 818 return B_OK; 819 } 820 821 /************************************************************* 822 * protected BMediaNode 823 *************************************************************/ 824 825 /* virtual */ status_t 826 BMediaNode::DeleteHook(BMediaNode *node) 827 { 828 CALLED(); 829 // Attention! We do not unregister TimeSourceObject nodes, 830 // since they are only a shadow object, and the real one still exists 831 if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0) 832 BMediaRoster::Roster()->UnregisterNode(this); 833 delete this; // delete "this" or "node", both are the same 834 return B_OK; 835 } 836 837 838 /* virtual */ void 839 BMediaNode::NodeRegistered() 840 { 841 CALLED(); 842 // The Media Server calls this hook function after the node has been registered. 843 // May be overriden by derived classes. 844 } 845 846 /************************************************************* 847 * public BMediaNode 848 *************************************************************/ 849 850 /* virtual */ status_t 851 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes, 852 size_t inMaxCount) 853 { 854 UNIMPLEMENTED(); 855 856 return B_ERROR; 857 } 858 859 860 /* virtual */ status_t 861 BMediaNode::AddTimer(bigtime_t at_performance_time, 862 int32 cookie) 863 { 864 UNIMPLEMENTED(); 865 866 return B_ERROR; 867 } 868 869 870 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; } 871 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; } 872 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; } 873 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; } 874 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; } 875 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; } 876 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; } 877 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; } 878 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; } 879 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; } 880 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; } 881 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; } 882 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; } 883 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; } 884 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; } 885 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; } 886 887 /* 888 private unimplemented 889 BMediaNode::BMediaNode() 890 BMediaNode::BMediaNode(const BMediaNode &clone) 891 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 892 */ 893 894 void 895 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) 896 { 897 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 898 899 fNodeID = id; 900 fRefCount = 1; 901 fName[0] = 0; 902 if (name) 903 strlcpy(fName, name, B_MEDIA_NAME_LENGTH); 904 fRunMode = B_INCREASE_LATENCY; 905 fKinds = kinds; 906 fProducerThis = 0; 907 fConsumerThis = 0; 908 fFileInterfaceThis = 0; 909 fControllableThis = 0; 910 fTimeSourceThis = 0; 911 912 // create control port 913 fControlPort = create_port(64, fName); 914 915 // nodes are assigned the system time source by default 916 fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; 917 918 // We can't create the timesource object here, because 919 // every timesource is a BMediaNode, which would result 920 // in infinite recursions 921 fTimeSource = NULL; 922 } 923 924 925 BMediaNode::BMediaNode(const char *name, 926 media_node_id id, 927 uint32 kinds) 928 { 929 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds); 930 _InitObject(name, id, kinds); 931 } 932 933 934 /************************************************************* 935 * protected BMediaNode 936 *************************************************************/ 937 938 /* static */ int32 939 BMediaNode::NewChangeTag() 940 { 941 CALLED(); 942 // change tags have been used in BeOS R4 to match up 943 // format change requests between producer and consumer, 944 // This has changed starting with R4.5 945 // now "change tags" are used with 946 // BMediaNode::RequestCompleted() 947 // and 948 // BBufferConsumer::RequestFormatChange() 949 // BBufferConsumer::SetOutputBuffersFor() 950 // BBufferConsumer::SetOutputEnabled() 951 // BBufferConsumer::SetVideoClippingFor() 952 return atomic_add(&BMediaNode::_m_changeTag,1); 953 } 954