1 /* 2 * Copyright (c) 2015, Dario Casalinuovo 3 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de> 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files or portions 7 * thereof (the "Software"), to deal in the Software without restriction, 8 * including without limitation the rights to use, copy, modify, merge, 9 * publish, distribute, sublicense, and/or sell copies of the Software, 10 * and to permit persons to whom the Software is furnished to do so, subject 11 * to the following conditions: 12 * 13 * * Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 16 * * Redistributions in binary form must reproduce the above copyright notice 17 * in the binary, as well as this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided with 19 * the distribution. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 * THE SOFTWARE. 28 * 29 */ 30 31 32 #include <BufferConsumer.h> 33 #include <BufferProducer.h> 34 #include <Controllable.h> 35 #include <FileInterface.h> 36 #include <MediaRoster.h> 37 #include <MediaNode.h> 38 #include <SupportDefs.h> 39 #include <TimeSource.h> 40 41 #include <string.h> 42 43 #include "DataExchange.h" 44 #include "debug.h" 45 #include "MediaMisc.h" 46 #include "MediaRosterEx.h" 47 #include "Notifications.h" 48 #include "ServerInterface.h" 49 #include "TimeSourceObject.h" 50 #include "TimeSourceObjectManager.h" 51 52 using std::nothrow; 53 using std::nothrow_t; 54 55 #undef TRACE 56 //#define TRACE_MEDIA_NODE 57 #ifdef TRACE_MEDIA_NODE 58 #define TRACE printf 59 #else 60 #define TRACE(x...) 61 #endif 62 63 // Don't rename this one, it's used and exported for binary compatibility 64 int32 BMediaNode::_m_changeTag = 0; 65 66 // media_node 67 68 media_node media_node::null; 69 70 media_node::media_node() 71 : 72 node(-1), 73 port(-1), 74 kind(0) 75 { 76 } 77 78 79 media_node::~media_node() 80 { 81 } 82 83 // media_input 84 85 media_input::media_input() 86 { 87 name[0] = '\0'; 88 } 89 90 91 media_input::~media_input() 92 { 93 } 94 95 // media_output 96 97 media_output::media_output() 98 { 99 name[0] = '\0'; 100 } 101 102 103 media_output::~media_output() 104 { 105 } 106 107 // live_node_info 108 109 live_node_info::live_node_info() 110 : 111 hint_point(0.0f, 0.0f) 112 { 113 name[0] = '\0'; 114 } 115 116 117 live_node_info::~live_node_info() 118 { 119 } 120 121 // BMediaNode 122 123 BMediaNode::~BMediaNode() 124 { 125 CALLED(); 126 // BeBook: UnregisterNode() unregisters a node from the Media Server. 127 // It's called automatically by the BMediaNode destructor, but it might 128 // be convenient to call it sometime before you delete your node instance, 129 // depending on your implementation and circumstances. 130 131 // First we remove the time source 132 if (fTimeSource) { 133 fTimeSource->RemoveMe(this); 134 fTimeSource->Release(); 135 fTimeSource = NULL; 136 } 137 138 // Attention! We do not delete their control ports, since they are only a 139 // shadow object, and the real one still exists 140 if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0) { 141 if (fControlPort > 0) 142 delete_port(fControlPort); 143 } else { 144 TRACE("BMediaNode::~BMediaNode: shadow timesource," 145 " not unregistering\n"); 146 } 147 } 148 149 150 BMediaNode* 151 BMediaNode::Acquire() 152 { 153 CALLED(); 154 atomic_add(&fRefCount,1); 155 return this; 156 } 157 158 159 BMediaNode* 160 BMediaNode::Release() 161 { 162 CALLED(); 163 if (atomic_add(&fRefCount, -1) == 1) { 164 TRACE("BMediaNode::Release() saving node %ld configuration\n", fNodeID); 165 MediaRosterEx(BMediaRoster::Roster())->SaveNodeConfiguration(this); 166 if (DeleteHook(this) != B_OK) { 167 ERROR("BMediaNode::Release(): DeleteHook failed\n"); 168 return Acquire(); 169 } 170 return NULL; 171 } 172 return this; 173 } 174 175 176 const char* 177 BMediaNode::Name() const 178 { 179 CALLED(); 180 return fName; 181 } 182 183 184 media_node_id 185 BMediaNode::ID() const 186 { 187 CALLED(); 188 return fNodeID; 189 } 190 191 192 uint64 193 BMediaNode::Kinds() const 194 { 195 CALLED(); 196 return fKinds & NODE_KIND_USER_MASK; 197 } 198 199 200 media_node 201 BMediaNode::Node() const 202 { 203 CALLED(); 204 media_node temp; 205 temp.node = ID(); 206 // We *must* call ControlPort(), some derived nodes 207 // use it to start the port read thread! 208 temp.port = ControlPort(); 209 temp.kind = Kinds(); 210 return temp; 211 } 212 213 214 BMediaNode::run_mode 215 BMediaNode::RunMode() const 216 { 217 CALLED(); 218 return fRunMode; 219 } 220 221 222 BTimeSource* 223 BMediaNode::TimeSource() const 224 { 225 PRINT(7, "CALLED BMediaNode::TimeSource()\n"); 226 227 // Return the currently assigned time source 228 if (fTimeSource != 0) 229 return fTimeSource; 230 231 TRACE("BMediaNode::TimeSource node %ld enter\n", ID()); 232 233 // If the node doesn't have a time source object, we need to create one. 234 // If the node is still unregistered, we can't call MakeTimeSourceFor(), 235 // but since the node does still have the default system time source, we 236 // can use GetSystemTimeSource 237 238 BMediaNode* self = const_cast<BMediaNode*>(this); 239 self->fTimeSource = MediaRosterEx( 240 BMediaRoster::Roster())->MakeTimeSourceObject(fTimeSourceID); 241 242 ASSERT(fTimeSource == self->fTimeSource); 243 244 if (fTimeSource == 0) { 245 ERROR("BMediaNode::TimeSource: MakeTimeSourceFor failed\n"); 246 } else { 247 ASSERT(fTimeSourceID == fTimeSource->ID()); 248 fTimeSource->AddMe(self); 249 } 250 251 TRACE("BMediaNode::TimeSource node %ld leave\n", ID()); 252 253 return fTimeSource; 254 } 255 256 257 port_id 258 BMediaNode::ControlPort() const 259 { 260 PRINT(7, "CALLED BMediaNode::ControlPort()\n"); 261 return fControlPort; 262 } 263 264 265 status_t 266 BMediaNode::ReportError(node_error what, const BMessage* info) 267 { 268 CALLED(); 269 270 // Sanity check the what value 271 switch (what) { 272 case BMediaNode::B_NODE_FAILED_START: 273 case BMediaNode::B_NODE_FAILED_STOP: 274 case BMediaNode::B_NODE_FAILED_SEEK: 275 case BMediaNode::B_NODE_FAILED_SET_RUN_MODE: 276 case BMediaNode::B_NODE_FAILED_TIME_WARP: 277 case BMediaNode::B_NODE_FAILED_PREROLL: 278 case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR: 279 case BMediaNode::B_NODE_IN_DISTRESS: 280 break; 281 default: 282 ERROR("BMediaNode::ReportError: invalid what!\n"); 283 return B_BAD_VALUE; 284 } 285 286 // Transmits the error code specified by what to anyone 287 // that's receiving notifications from this node 288 return BPrivate::media::notifications::ReportError(Node(), what, info); 289 } 290 291 292 status_t 293 BMediaNode::NodeStopped(bigtime_t whenPerformance) 294 { 295 UNIMPLEMENTED(); 296 // Called by derived classes when they have 297 // finished handling a stop request. 298 299 // Notify anyone who is listening for stop notifications! 300 BPrivate::media::notifications::NodeStopped(Node(), whenPerformance); 301 302 // NOTE: If your node is a BBufferProducer, downstream consumers 303 // will be notified that your node stopped (automatically, no less) through 304 // the BBufferConsumer::ProducerDataStatus(B_PRODUCER_STOPPED) call. 305 306 return B_OK; 307 } 308 309 310 /* 311 * Used in couple with AddTimer, this will cause the BMediaRoster::SyncToNode() 312 * call that requested the timer to return to the caller with an appropriate 313 * value. 314 */ 315 void 316 BMediaNode::TimerExpired(bigtime_t notifyPoint, int32 cookie, status_t error) 317 { 318 CALLED(); 319 if (write_port((port_id)cookie, 0, &error, sizeof(error)) < 0) { 320 TRACE("BMediaNode::TimerExpired: error writing port" B_PRId32 321 ", at notifyPoint" B_PRId64 "\n", cookie, notifyPoint); 322 } 323 } 324 325 326 BMediaNode::BMediaNode(const char* name) 327 { 328 TRACE("BMediaNode::BMediaNode: name '%s'\n", name); 329 _InitObject(name, NODE_JUST_CREATED_ID, 0); 330 } 331 332 333 status_t 334 BMediaNode::WaitForMessage(bigtime_t waitUntil, uint32 flags, 335 void* _reserved_) 336 { 337 TRACE("entering: BMediaNode::WaitForMessage()\n"); 338 339 // This function waits until either real time specified by 340 // waitUntil or a message is received on the control port. 341 // The flags are currently unused and should be 0. 342 // Note: about 16 KByte stack used 343 char data[B_MEDIA_MESSAGE_SIZE]; 344 int32 message; 345 ssize_t size; 346 while (true) { 347 size = read_port_etc(ControlPort(), &message, data, 348 sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil); 349 350 if (size >= 0) 351 break; 352 353 status_t error = (status_t)size; 354 if (error == B_INTERRUPTED) 355 continue; 356 357 if (error != B_TIMED_OUT && error != B_BAD_PORT_ID) { 358 ERROR("BMediaNode::WaitForMessage: read_port_etc error: %s\n", 359 strerror(error)); 360 } 361 362 return error; 363 } 364 365 TRACE("BMediaNode::WaitForMessage request is: %#lx, node %ld, this %p\n", 366 message, fNodeID, this); 367 368 if (message == GENERAL_PURPOSE_WAKEUP) 369 return B_OK; 370 371 if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { 372 TRACE("BMediaNode::WaitForMessage calling BMediaNode\n"); 373 374 if (B_OK == BMediaNode::HandleMessage(message, data, size)) 375 return B_OK; 376 } 377 378 if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) { 379 if (!fProducerThis) 380 fProducerThis = dynamic_cast<BBufferProducer*>(this); 381 382 TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", 383 fProducerThis); 384 385 if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage( 386 message, data, size) == B_OK) { 387 return B_OK; 388 } 389 } 390 391 if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) { 392 if (!fConsumerThis) 393 fConsumerThis = dynamic_cast<BBufferConsumer*>(this); 394 395 TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", 396 fConsumerThis); 397 398 if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage( 399 message, data, size) == B_OK) { 400 return B_OK; 401 } 402 } 403 404 if (message > FILEINTERFACE_MESSAGE_START 405 && message < FILEINTERFACE_MESSAGE_END) { 406 if (!fFileInterfaceThis) 407 fFileInterfaceThis = dynamic_cast<BFileInterface*>(this); 408 409 TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", 410 fFileInterfaceThis); 411 412 if (fFileInterfaceThis 413 && fFileInterfaceThis->BFileInterface::HandleMessage( 414 message, data, size) == B_OK) { 415 return B_OK; 416 } 417 } 418 419 if (message > CONTROLLABLE_MESSAGE_START 420 && message < CONTROLLABLE_MESSAGE_END) { 421 if (!fControllableThis) 422 fControllableThis = dynamic_cast<BControllable*>(this); 423 424 TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", 425 fControllableThis); 426 427 if (fControllableThis 428 && fControllableThis->BControllable::HandleMessage( 429 message, data, size) == B_OK) { 430 return B_OK; 431 } 432 } 433 434 if (message > TIMESOURCE_MESSAGE_START 435 && message < TIMESOURCE_MESSAGE_END) { 436 if (!fTimeSourceThis) 437 fTimeSourceThis = dynamic_cast<BTimeSource*>(this); 438 439 TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", 440 fTimeSourceThis); 441 442 if (fTimeSourceThis && fTimeSourceThis->BTimeSource::HandleMessage( 443 message, data, size) == B_OK) { 444 return B_OK; 445 } 446 } 447 448 TRACE("BMediaNode::WaitForMessage calling default HandleMessage\n"); 449 if (HandleMessage(message, data, size) == B_OK) 450 return B_OK; 451 452 HandleBadMessage(message, data, size); 453 454 return B_ERROR; 455 } 456 457 458 void 459 BMediaNode::Start(bigtime_t performance_time) 460 { 461 CALLED(); 462 // This hook function is called when a node is started 463 // by a call to the BMediaRoster. The specified 464 // performanceTime, the time at which the node 465 // should start running, may be in the future. 466 // It may be overriden by derived classes. 467 // The BMediaEventLooper class handles this event! 468 // The BMediaNode class does nothing here. 469 } 470 471 472 void 473 BMediaNode::Stop(bigtime_t performance_time, bool immediate) 474 { 475 CALLED(); 476 // This hook function is called when a node is stopped 477 // by a call to the BMediaRoster. The specified 478 // performanceTime, the time at which the node 479 // should stop running, may be in the future. 480 // It may be overriden by derived classes. 481 // The BMediaEventLooper class handles this event! 482 // The BMediaNode class does nothing here. 483 } 484 485 486 void 487 BMediaNode::Seek(bigtime_t media_time, bigtime_t performance_time) 488 { 489 CALLED(); 490 // This hook function is called when a node is asked 491 // to seek to the specified mediaTime by a call to 492 // the BMediaRoster. The specified performanceTime, 493 // the time at which the node should begin the seek 494 // operation, may be in the future. 495 // It may be overriden by derived classes. 496 // The BMediaEventLooper class handles this event! 497 // The BMediaNode class does nothing here. 498 } 499 500 501 void 502 BMediaNode::SetRunMode(run_mode mode) 503 { 504 CALLED(); 505 506 // This is a hook function, and 507 // may be overriden by derived classes. 508 509 // The functionality here is only to 510 // support those people that don't 511 // use the roster to set the run mode 512 fRunMode = mode; 513 } 514 515 516 void 517 BMediaNode::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 518 { 519 CALLED(); 520 // May be overriden by derived classes. 521 } 522 523 524 void 525 BMediaNode::Preroll() 526 { 527 CALLED(); 528 // May be overriden by derived classes. 529 } 530 531 532 void 533 BMediaNode::SetTimeSource(BTimeSource* time_source) 534 { 535 CALLED(); 536 // This is a hook function, and 537 // may be overriden by derived classes. 538 539 if (time_source == NULL || time_source == fTimeSource) 540 return; 541 542 // We just trip into debugger, code that tries to do this is broken. 543 debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, " 544 "use BMediaRoster::SetTimeSourceFor()!\n"); 545 } 546 547 548 status_t 549 BMediaNode::HandleMessage(int32 message, const void* data, size_t size) 550 { 551 TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID); 552 switch (message) { 553 case NODE_FINAL_RELEASE: 554 { 555 TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", 556 this); 557 558 // This is called by the media server to delete the object 559 // after is has been released by all nodes that are using it. 560 // We forward the function to the BMediaRoster, since the 561 // deletion must be done from a different thread, or the 562 // outermost destructor that will exit the thread that is 563 // reading messages from the port (this thread contex) will 564 // quit, and ~BMediaNode destructor won't be called ever. 565 BMessage msg(NODE_FINAL_RELEASE); 566 msg.AddPointer("node", this); 567 BMediaRoster::Roster()->PostMessage(&msg); 568 return B_OK; 569 } 570 571 case NODE_START: 572 { 573 const node_start_command* command 574 = static_cast<const node_start_command*>(data); 575 TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID); 576 Start(command->performance_time); 577 return B_OK; 578 } 579 580 case NODE_STOP: 581 { 582 const node_stop_command* command 583 = static_cast<const node_stop_command*>(data); 584 TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID); 585 Stop(command->performance_time, command->immediate); 586 return B_OK; 587 } 588 589 case NODE_SEEK: 590 { 591 const node_seek_command* command 592 = static_cast<const node_seek_command*>(data); 593 TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID); 594 Seek(command->media_time, command->performance_time); 595 return B_OK; 596 } 597 598 case NODE_SET_RUN_MODE: 599 { 600 const node_set_run_mode_command* command 601 = static_cast<const node_set_run_mode_command*>(data); 602 TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE," 603 " node %ld\n", fNodeID); 604 // Need to change PRODUCER_SET_RUN_MODE_DELAY 605 fRunMode = command->mode; 606 SetRunMode(fRunMode); 607 return B_OK; 608 } 609 610 case NODE_TIME_WARP: 611 { 612 const node_time_warp_command* command 613 = static_cast<const node_time_warp_command*>(data); 614 TRACE("BMediaNode::HandleMessage NODE_TIME_WARP," 615 " node %ld\n", fNodeID); 616 TimeWarp(command->at_real_time, command->to_performance_time); 617 return B_OK; 618 } 619 620 case NODE_PREROLL: 621 { 622 TRACE("BMediaNode::HandleMessage NODE_PREROLL, " 623 " node %ld\n", fNodeID); 624 Preroll(); 625 return B_OK; 626 } 627 628 case NODE_ROLL: 629 { 630 const node_roll_command* command 631 = static_cast<const node_roll_command*>(data); 632 633 TRACE("BMediaNode::HandleMessage NODE_ROLL, node %ld\n", 634 fNodeID); 635 636 if (command->seek_media_time != B_INFINITE_TIMEOUT) 637 Seek(command->seek_media_time, 638 command->start_performance_time); 639 640 Start(command->start_performance_time); 641 Stop(command->stop_performance_time, false); 642 return B_OK; 643 } 644 645 case NODE_SYNC_TO: 646 { 647 const node_sync_to_request* request 648 = static_cast<const node_sync_to_request*>(data); 649 node_sync_to_reply reply; 650 651 TRACE("BMediaNode::HandleMessage NODE_SYNC_TO, node %ld\n", 652 fNodeID); 653 654 // If AddTimer return an error the caller will know that the node 655 // doesn't support this feature or there was a problem when adding 656 // it, this will result in SyncToNode returning immediately 657 // to the caller with an error. 658 status_t status = AddTimer(request->performance_time, 659 request->port); 660 661 request->SendReply(status, &reply, sizeof(reply)); 662 return B_OK; 663 } 664 665 case NODE_SET_TIMESOURCE: 666 { 667 const node_set_timesource_command* command 668 = static_cast<const node_set_timesource_command*>(data); 669 670 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE," 671 " node %ld, timesource %ld enter\n", 672 fNodeID, command->timesource_id); 673 674 fTimeSourceID = command->timesource_id; 675 676 if (fTimeSource) { 677 // As this node already had a timesource, to remove this node 678 // from time source control 679 fTimeSource->RemoveMe(this); 680 // Release the time source 681 fTimeSource->Release(); 682 // Force next call to TimeSource() to create a new object 683 fTimeSource = 0; 684 } 685 686 // Create new time source object and call the SetTimeSource 687 // hook function to notify any derived class 688 fTimeSource = TimeSource(); 689 SetTimeSource(fTimeSource); 690 691 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld," 692 "timesource %ld leave\n", fNodeID, command->timesource_id); 693 694 return B_OK; 695 } 696 697 case NODE_GET_TIMESOURCE: 698 { 699 const node_get_timesource_request* request 700 = static_cast<const node_get_timesource_request*>(data); 701 702 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE," 703 " node %ld\n", fNodeID); 704 705 node_get_timesource_reply reply; 706 reply.timesource_id = fTimeSourceID; 707 request->SendReply(B_OK, &reply, sizeof(reply)); 708 return B_OK; 709 } 710 711 case NODE_GET_ATTRIBUTES_FOR: 712 { 713 const node_get_attributes_for_request *request = 714 (const node_get_attributes_for_request*) data; 715 716 TRACE("BMediaNode::HandleMessage NODE_GET_ATTRIBUTES_FOR," 717 "node %ld\n", fNodeID); 718 719 node_get_attributes_for_reply reply; 720 721 media_node_attribute* addr; 722 area_id dataArea = clone_area("client attributes area", 723 (void**)&addr, B_ANY_ADDRESS, B_WRITE_AREA, 724 request->area); 725 726 if (dataArea < 0) { 727 ERROR("NODE_GET_ATTRIBUTES_FOR can't clone area\n"); 728 return B_NO_MEMORY; 729 } 730 731 status_t status = GetNodeAttributes(addr, request->count); 732 if (status == B_OK) { 733 // NOTE: we do it because there's not an easy way 734 // to guess the number of attributes filled. 735 size_t i; 736 for (i = 0; i < request->count; i++) { 737 if (addr[i].what <= 0) 738 break; 739 } 740 reply.filled_count = i; 741 } 742 request->SendReply(status, &reply, sizeof(reply)); 743 delete_area(dataArea); 744 return B_OK; 745 } 746 747 case NODE_REQUEST_COMPLETED: 748 { 749 const node_request_completed_command* command 750 = static_cast<const node_request_completed_command*>(data); 751 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED," 752 " node %ld\n", fNodeID); 753 RequestCompleted(command->info); 754 return B_OK; 755 } 756 757 default: 758 return B_ERROR; 759 760 } 761 return B_ERROR; 762 } 763 764 765 void 766 BMediaNode::HandleBadMessage(int32 code, const void* buffer, size_t size) 767 { 768 CALLED(); 769 770 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", 771 code, buffer, size); 772 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 773 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 774 } else { 775 // All messages targeted to nodes should be handled here, 776 // messages targetted to the wrong node should be handled 777 // by returning an error, not by stalling the sender. 778 const request_data* request = static_cast<const request_data* >(buffer); 779 reply_data reply; 780 request->SendReply(B_ERROR, &reply, sizeof(reply)); 781 } 782 } 783 784 785 void 786 BMediaNode::AddNodeKind(uint64 kind) 787 { 788 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 789 fKinds |= kind; 790 } 791 792 793 void* 794 BMediaNode::operator new(size_t size) 795 { 796 CALLED(); 797 return ::operator new(size); 798 } 799 800 801 void* 802 BMediaNode::operator new(size_t size, const nothrow_t&) throw() 803 { 804 CALLED(); 805 return ::operator new(size, nothrow); 806 } 807 808 809 void 810 BMediaNode::operator delete(void* ptr) 811 { 812 CALLED(); 813 ::operator delete(ptr); 814 } 815 816 817 void 818 BMediaNode::operator delete(void* ptr, const nothrow_t&) throw() 819 { 820 CALLED(); 821 ::operator delete(ptr, nothrow); 822 } 823 824 825 status_t 826 BMediaNode::RequestCompleted(const media_request_info& info) 827 { 828 CALLED(); 829 // This function is called whenever 830 // a request issued by the node is completed. 831 // May be overriden by derived classes. 832 // info.change_tag can be used to match up requests against 833 // the accompaning calles from 834 // BBufferConsumer::RequestFormatChange() 835 // BBufferConsumer::SetOutputBuffersFor() 836 // BBufferConsumer::SetOutputEnabled() 837 // BBufferConsumer::SetVideoClippingFor() 838 return B_OK; 839 } 840 841 842 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 void 856 BMediaNode::NodeRegistered() 857 { 858 CALLED(); 859 // The Media Server calls this hook function 860 // after the node has been registered. 861 // May be overriden by derived classes. 862 } 863 864 865 status_t 866 BMediaNode::GetNodeAttributes(media_node_attribute* outAttributes, 867 size_t inMaxCount) 868 { 869 CALLED(); 870 // This is implemented by derived classes that fills 871 // it's own attributes to a max of inMaxCount elements. 872 return B_ERROR; 873 } 874 875 876 status_t 877 BMediaNode::AddTimer(bigtime_t at_performance_time, int32 cookie) 878 { 879 CALLED(); 880 return B_ERROR; 881 } 882 883 884 status_t BMediaNode::_Reserved_MediaNode_0(void*) { return B_ERROR; } 885 status_t BMediaNode::_Reserved_MediaNode_1(void*) { return B_ERROR; } 886 status_t BMediaNode::_Reserved_MediaNode_2(void*) { return B_ERROR; } 887 status_t BMediaNode::_Reserved_MediaNode_3(void*) { return B_ERROR; } 888 status_t BMediaNode::_Reserved_MediaNode_4(void*) { return B_ERROR; } 889 status_t BMediaNode::_Reserved_MediaNode_5(void*) { return B_ERROR; } 890 status_t BMediaNode::_Reserved_MediaNode_6(void*) { return B_ERROR; } 891 status_t BMediaNode::_Reserved_MediaNode_7(void*) { return B_ERROR; } 892 status_t BMediaNode::_Reserved_MediaNode_8(void*) { return B_ERROR; } 893 status_t BMediaNode::_Reserved_MediaNode_9(void*) { return B_ERROR; } 894 status_t BMediaNode::_Reserved_MediaNode_10(void*) { return B_ERROR; } 895 status_t BMediaNode::_Reserved_MediaNode_11(void*) { return B_ERROR; } 896 status_t BMediaNode::_Reserved_MediaNode_12(void*) { return B_ERROR; } 897 status_t BMediaNode::_Reserved_MediaNode_13(void*) { return B_ERROR; } 898 status_t BMediaNode::_Reserved_MediaNode_14(void*) { return B_ERROR; } 899 status_t BMediaNode::_Reserved_MediaNode_15(void*) { return B_ERROR; } 900 901 /* 902 private unimplemented 903 BMediaNode::BMediaNode() 904 BMediaNode::BMediaNode(const BMediaNode &clone) 905 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 906 */ 907 908 void 909 BMediaNode::_InitObject(const char* name, media_node_id id, uint64 kinds) 910 { 911 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 912 913 fNodeID = id; 914 fRefCount = 1; 915 fName[0] = 0; 916 if (name) 917 strlcpy(fName, name, B_MEDIA_NAME_LENGTH); 918 fRunMode = B_INCREASE_LATENCY; 919 fKinds = kinds; 920 fProducerThis = 0; 921 fConsumerThis = 0; 922 fFileInterfaceThis = 0; 923 fControllableThis = 0; 924 fTimeSourceThis = 0; 925 926 // Create control port 927 fControlPort = create_port(64, fName); 928 929 // Nodes are assigned the system time source by default 930 fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; 931 932 // We can't create the timesource object here, because 933 // every timesource is a BMediaNode, which would result 934 // in infinite recursions 935 fTimeSource = NULL; 936 } 937 938 939 BMediaNode::BMediaNode(const char* name, media_node_id id, uint32 kinds) 940 { 941 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", 942 name, id, kinds); 943 _InitObject(name, id, kinds); 944 } 945 946 947 int32 948 BMediaNode::NewChangeTag() 949 { 950 CALLED(); 951 // Change tags have been used in BeOS R4 to match up 952 // format change requests between producer and consumer, 953 // This has changed starting with R4.5 954 // now "change tags" are used with the following functions: 955 // BMediaNode::RequestCompleted() 956 // BBufferConsumer::RequestFormatChange() 957 // BBufferConsumer::SetOutputBuffersFor() 958 // BBufferConsumer::SetOutputEnabled() 959 // BBufferConsumer::SetVideoClippingFor() 960 return atomic_add(&BMediaNode::_m_changeTag,1); 961 } 962 963 // BeOS R4 deprecated API 964 965 int32 966 BMediaNode::IncrementChangeTag() 967 { 968 CALLED(); 969 // Only present in BeOS R4 970 // Obsoleted in BeOS R4.5 and later 971 // "updates the change tag, so that downstream consumers 972 // know that the node is in a new state." 973 // not supported, only for binary compatibility 974 return 0; 975 } 976 977 978 int32 979 BMediaNode::ChangeTag() 980 { 981 UNIMPLEMENTED(); 982 // Only present in BeOS R4 983 // Obsoleted in BeOS R4.5 and later 984 // "returns the node's current change tag value." 985 // not supported, only for binary compatibility 986 return 0; 987 } 988 989 990 int32 991 BMediaNode::MintChangeTag() 992 { 993 UNIMPLEMENTED(); 994 // Only present in BeOS R4 995 // Obsoleted in BeOS R4.5 and later 996 // "mints a new, reserved, change tag." 997 // "Call ApplyChangeTag() to apply it to the node" 998 // not supported, only for binary compatibility 999 return 0; 1000 } 1001 1002 1003 status_t 1004 BMediaNode::ApplyChangeTag(int32 previously_reserved) 1005 { 1006 UNIMPLEMENTED(); 1007 // Only present in BeOS R4 1008 // Obsoleted in BeOS R4.5 and later 1009 // "this returns B_OK if the new change tag is" 1010 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 1011 // "count you tried to apply is already obsolete." 1012 // not supported, only for binary compatibility 1013 return B_OK; 1014 } 1015