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_ROLL: 636 { 637 const node_roll_command *command 638 = static_cast<const node_roll_command *>(data); 639 640 TRACE("BMediaNode::HandleMessage NODE_ROLL, node %ld\n", 641 fNodeID); 642 643 if (command->seek_media_time != B_INFINITE_TIMEOUT) 644 Seek(command->seek_media_time, 645 command->start_performance_time); 646 647 Start(command->start_performance_time); 648 Stop(command->stop_performance_time, false); 649 return B_OK; 650 } 651 652 case NODE_SET_TIMESOURCE: 653 { 654 const node_set_timesource_command *command = static_cast<const node_set_timesource_command *>(data); 655 656 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id); 657 658 fTimeSourceID = command->timesource_id; 659 660 if (fTimeSource) { 661 // as this node already had a timesource, we need 662 // we need to remove this node from time source control 663 fTimeSource->RemoveMe(this); 664 // Then release the time source 665 fTimeSource->Release(); 666 // force next call to TimeSource() to create a new object 667 fTimeSource = 0; 668 } 669 670 // create new time source object 671 fTimeSource = TimeSource(); 672 // and call the SetTimeSource hook function to notify 673 // any derived class 674 SetTimeSource(fTimeSource); 675 676 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id); 677 678 return B_OK; 679 } 680 681 case NODE_GET_TIMESOURCE: 682 { 683 const node_get_timesource_request *request = static_cast<const node_get_timesource_request *>(data); 684 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE, node %ld\n", fNodeID); 685 node_get_timesource_reply reply; 686 reply.timesource_id = fTimeSourceID; 687 request->SendReply(B_OK, &reply, sizeof(reply)); 688 return B_OK; 689 } 690 691 case NODE_REQUEST_COMPLETED: 692 { 693 const node_request_completed_command *command = static_cast<const node_request_completed_command *>(data); 694 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED, node %ld\n", fNodeID); 695 RequestCompleted(command->info); 696 return B_OK; 697 } 698 699 }; 700 return B_ERROR; 701 } 702 703 704 void 705 BMediaNode::HandleBadMessage(int32 code, 706 const void *buffer, 707 size_t size) 708 { 709 CALLED(); 710 711 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", code, buffer, size); 712 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 713 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 714 } else { 715 /* All messages targeted to nodes should be handled here, 716 * messages targetted to the wrong node should be handled 717 * by returning an error, not by stalling the sender. 718 */ 719 const request_data *request = static_cast<const request_data *>(buffer); 720 reply_data reply; 721 request->SendReply(B_ERROR, &reply, sizeof(reply)); 722 } 723 } 724 725 726 void 727 BMediaNode::AddNodeKind(uint64 kind) 728 { 729 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 730 731 fKinds |= kind; 732 } 733 734 735 void * 736 BMediaNode::operator new(size_t size) 737 { 738 CALLED(); 739 return ::operator new(size); 740 } 741 742 void * 743 BMediaNode::operator new(size_t size, 744 const nothrow_t &) throw() 745 { 746 CALLED(); 747 return ::operator new(size, nothrow); 748 } 749 750 void 751 BMediaNode::operator delete(void *ptr) 752 { 753 CALLED(); 754 ::operator delete(ptr); 755 } 756 757 void 758 BMediaNode::operator delete(void * ptr, 759 const nothrow_t &) throw() 760 { 761 CALLED(); 762 ::operator delete(ptr, nothrow); 763 } 764 765 /************************************************************* 766 * protected BMediaNode 767 *************************************************************/ 768 769 /* virtual */ status_t 770 BMediaNode::RequestCompleted(const media_request_info &info) 771 { 772 CALLED(); 773 // This function is called whenever a request issued by the node is completed. 774 // May be overriden by derived classes. 775 // info.change_tag can be used to match up requests against 776 // the accompaning calles from 777 // BBufferConsumer::RequestFormatChange() 778 // BBufferConsumer::SetOutputBuffersFor() 779 // BBufferConsumer::SetOutputEnabled() 780 // BBufferConsumer::SetVideoClippingFor() 781 return B_OK; 782 } 783 784 /************************************************************* 785 * private BMediaNode 786 *************************************************************/ 787 788 int32 789 BMediaNode::IncrementChangeTag() 790 { 791 CALLED(); 792 // Only present in BeOS R4 793 // Obsoleted in BeOS R4.5 and later 794 // "updates the change tag, so that downstream consumers know that the node is in a new state." 795 // not supported, only for binary compatibility 796 return 0; 797 } 798 799 800 int32 801 BMediaNode::ChangeTag() 802 { 803 UNIMPLEMENTED(); 804 // Only present in BeOS R4 805 // Obsoleted in BeOS R4.5 and later 806 // "returns the node's current change tag value." 807 // not supported, only for binary compatibility 808 return 0; 809 } 810 811 812 int32 813 BMediaNode::MintChangeTag() 814 { 815 UNIMPLEMENTED(); 816 // Only present in BeOS R4 817 // Obsoleted in BeOS R4.5 and later 818 // "mints a new, reserved, change tag." 819 // "Call ApplyChangeTag() to apply it to the node" 820 // not supported, only for binary compatibility 821 return 0; 822 } 823 824 825 status_t 826 BMediaNode::ApplyChangeTag(int32 previously_reserved) 827 { 828 UNIMPLEMENTED(); 829 // Only present in BeOS R4 830 // Obsoleted in BeOS R4.5 and later 831 // "this returns B_OK if the new change tag is" 832 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 833 // "count you tried to apply is already obsolete." 834 // not supported, only for binary compatibility 835 return B_OK; 836 } 837 838 /************************************************************* 839 * protected BMediaNode 840 *************************************************************/ 841 842 /* virtual */ status_t 843 BMediaNode::DeleteHook(BMediaNode *node) 844 { 845 CALLED(); 846 // Attention! We do not unregister TimeSourceObject nodes, 847 // since they are only a shadow object, and the real one still exists 848 if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0) 849 BMediaRoster::Roster()->UnregisterNode(this); 850 delete this; // delete "this" or "node", both are the same 851 return B_OK; 852 } 853 854 855 /* virtual */ void 856 BMediaNode::NodeRegistered() 857 { 858 CALLED(); 859 // The Media Server calls this hook function after the node has been registered. 860 // May be overriden by derived classes. 861 } 862 863 /************************************************************* 864 * public BMediaNode 865 *************************************************************/ 866 867 /* virtual */ status_t 868 BMediaNode::GetNodeAttributes(media_node_attribute *outAttributes, 869 size_t inMaxCount) 870 { 871 UNIMPLEMENTED(); 872 873 return B_ERROR; 874 } 875 876 877 /* virtual */ status_t 878 BMediaNode::AddTimer(bigtime_t at_performance_time, 879 int32 cookie) 880 { 881 UNIMPLEMENTED(); 882 883 return B_ERROR; 884 } 885 886 887 status_t BMediaNode::_Reserved_MediaNode_0(void *) { return B_ERROR; } 888 status_t BMediaNode::_Reserved_MediaNode_1(void *) { return B_ERROR; } 889 status_t BMediaNode::_Reserved_MediaNode_2(void *) { return B_ERROR; } 890 status_t BMediaNode::_Reserved_MediaNode_3(void *) { return B_ERROR; } 891 status_t BMediaNode::_Reserved_MediaNode_4(void *) { return B_ERROR; } 892 status_t BMediaNode::_Reserved_MediaNode_5(void *) { return B_ERROR; } 893 status_t BMediaNode::_Reserved_MediaNode_6(void *) { return B_ERROR; } 894 status_t BMediaNode::_Reserved_MediaNode_7(void *) { return B_ERROR; } 895 status_t BMediaNode::_Reserved_MediaNode_8(void *) { return B_ERROR; } 896 status_t BMediaNode::_Reserved_MediaNode_9(void *) { return B_ERROR; } 897 status_t BMediaNode::_Reserved_MediaNode_10(void *) { return B_ERROR; } 898 status_t BMediaNode::_Reserved_MediaNode_11(void *) { return B_ERROR; } 899 status_t BMediaNode::_Reserved_MediaNode_12(void *) { return B_ERROR; } 900 status_t BMediaNode::_Reserved_MediaNode_13(void *) { return B_ERROR; } 901 status_t BMediaNode::_Reserved_MediaNode_14(void *) { return B_ERROR; } 902 status_t BMediaNode::_Reserved_MediaNode_15(void *) { return B_ERROR; } 903 904 /* 905 private unimplemented 906 BMediaNode::BMediaNode() 907 BMediaNode::BMediaNode(const BMediaNode &clone) 908 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 909 */ 910 911 void 912 BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) 913 { 914 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 915 916 fNodeID = id; 917 fRefCount = 1; 918 fName[0] = 0; 919 if (name) 920 strlcpy(fName, name, B_MEDIA_NAME_LENGTH); 921 fRunMode = B_INCREASE_LATENCY; 922 fKinds = kinds; 923 fProducerThis = 0; 924 fConsumerThis = 0; 925 fFileInterfaceThis = 0; 926 fControllableThis = 0; 927 fTimeSourceThis = 0; 928 929 // create control port 930 fControlPort = create_port(64, fName); 931 932 // nodes are assigned the system time source by default 933 fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; 934 935 // We can't create the timesource object here, because 936 // every timesource is a BMediaNode, which would result 937 // in infinite recursions 938 fTimeSource = NULL; 939 } 940 941 942 BMediaNode::BMediaNode(const char *name, 943 media_node_id id, 944 uint32 kinds) 945 { 946 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", name, id, kinds); 947 _InitObject(name, id, kinds); 948 } 949 950 951 /************************************************************* 952 * protected BMediaNode 953 *************************************************************/ 954 955 /* static */ int32 956 BMediaNode::NewChangeTag() 957 { 958 CALLED(); 959 // change tags have been used in BeOS R4 to match up 960 // format change requests between producer and consumer, 961 // This has changed starting with R4.5 962 // now "change tags" are used with 963 // BMediaNode::RequestCompleted() 964 // and 965 // BBufferConsumer::RequestFormatChange() 966 // BBufferConsumer::SetOutputBuffersFor() 967 // BBufferConsumer::SetOutputEnabled() 968 // BBufferConsumer::SetVideoClippingFor() 969 return atomic_add(&BMediaNode::_m_changeTag,1); 970 } 971