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