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