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 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 // TODO: Investigate on this issue 366 if (waitUntil < 0) { 367 TRACE("BMediaNode::WaitForMessage: Negative timeout!\n"); 368 waitUntil = 0; 369 } 370 371 while (true) { 372 size = read_port_etc(ControlPort(), &message, data, 373 sizeof(data), B_ABSOLUTE_TIMEOUT, waitUntil); 374 375 if (size >= 0) 376 break; 377 378 status_t error = (status_t)size; 379 if (error == B_INTERRUPTED) 380 continue; 381 382 if (error != B_TIMED_OUT && error != B_BAD_PORT_ID) { 383 ERROR("BMediaNode::WaitForMessage: read_port_etc error: %s\n", 384 strerror(error)); 385 } 386 387 return error; 388 } 389 390 TRACE("BMediaNode::WaitForMessage request is: %#lx, node %ld, this %p\n", 391 message, fNodeID, this); 392 393 if (message == GENERAL_PURPOSE_WAKEUP) 394 return B_OK; 395 396 if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { 397 TRACE("BMediaNode::WaitForMessage calling BMediaNode\n"); 398 399 if (B_OK == BMediaNode::HandleMessage(message, data, size)) 400 return B_OK; 401 } 402 403 if (message > PRODUCER_MESSAGE_START && message < PRODUCER_MESSAGE_END) { 404 if (!fProducerThis) 405 fProducerThis = dynamic_cast<BBufferProducer*>(this); 406 407 TRACE("BMediaNode::WaitForMessage calling BBufferProducer %p\n", 408 fProducerThis); 409 410 if (fProducerThis && fProducerThis->BBufferProducer::HandleMessage( 411 message, data, size) == B_OK) { 412 return B_OK; 413 } 414 } 415 416 if (message > CONSUMER_MESSAGE_START && message < CONSUMER_MESSAGE_END) { 417 if (!fConsumerThis) 418 fConsumerThis = dynamic_cast<BBufferConsumer*>(this); 419 420 TRACE("BMediaNode::WaitForMessage calling BBufferConsumer %p\n", 421 fConsumerThis); 422 423 if (fConsumerThis && fConsumerThis->BBufferConsumer::HandleMessage( 424 message, data, size) == B_OK) { 425 return B_OK; 426 } 427 } 428 429 if (message > FILEINTERFACE_MESSAGE_START 430 && message < FILEINTERFACE_MESSAGE_END) { 431 if (!fFileInterfaceThis) 432 fFileInterfaceThis = dynamic_cast<BFileInterface*>(this); 433 434 TRACE("BMediaNode::WaitForMessage calling BFileInterface %p\n", 435 fFileInterfaceThis); 436 437 if (fFileInterfaceThis 438 && fFileInterfaceThis->BFileInterface::HandleMessage( 439 message, data, size) == B_OK) { 440 return B_OK; 441 } 442 } 443 444 if (message > CONTROLLABLE_MESSAGE_START 445 && message < CONTROLLABLE_MESSAGE_END) { 446 if (!fControllableThis) 447 fControllableThis = dynamic_cast<BControllable*>(this); 448 449 TRACE("BMediaNode::WaitForMessage calling BControllable %p\n", 450 fControllableThis); 451 452 if (fControllableThis 453 && fControllableThis->BControllable::HandleMessage( 454 message, data, size) == B_OK) { 455 return B_OK; 456 } 457 } 458 459 if (message > TIMESOURCE_MESSAGE_START 460 && message < TIMESOURCE_MESSAGE_END) { 461 if (!fTimeSourceThis) 462 fTimeSourceThis = dynamic_cast<BTimeSource*>(this); 463 464 TRACE("BMediaNode::WaitForMessage calling BTimeSource %p\n", 465 fTimeSourceThis); 466 467 if (fTimeSourceThis && fTimeSourceThis->BTimeSource::HandleMessage( 468 message, data, size) == B_OK) { 469 return B_OK; 470 } 471 } 472 473 TRACE("BMediaNode::WaitForMessage calling default HandleMessage\n"); 474 if (HandleMessage(message, data, size) == B_OK) 475 return B_OK; 476 477 HandleBadMessage(message, data, size); 478 479 return B_ERROR; 480 } 481 482 483 void 484 BMediaNode::Start(bigtime_t performance_time) 485 { 486 CALLED(); 487 // This hook function is called when a node is started 488 // by a call to the BMediaRoster. The specified 489 // performanceTime, the time at which the node 490 // should start running, may be in the future. 491 // It may be overriden by derived classes. 492 // The BMediaEventLooper class handles this event! 493 // The BMediaNode class does nothing here. 494 } 495 496 497 void 498 BMediaNode::Stop(bigtime_t performance_time, bool immediate) 499 { 500 CALLED(); 501 // This hook function is called when a node is stopped 502 // by a call to the BMediaRoster. The specified 503 // performanceTime, the time at which the node 504 // should stop running, may be in the future. 505 // It may be overriden by derived classes. 506 // The BMediaEventLooper class handles this event! 507 // The BMediaNode class does nothing here. 508 } 509 510 511 void 512 BMediaNode::Seek(bigtime_t media_time, bigtime_t performance_time) 513 { 514 CALLED(); 515 // This hook function is called when a node is asked 516 // to seek to the specified mediaTime by a call to 517 // the BMediaRoster. The specified performanceTime, 518 // the time at which the node should begin the seek 519 // operation, may be in the future. 520 // It may be overriden by derived classes. 521 // The BMediaEventLooper class handles this event! 522 // The BMediaNode class does nothing here. 523 } 524 525 526 void 527 BMediaNode::SetRunMode(run_mode mode) 528 { 529 CALLED(); 530 531 // This is a hook function, and 532 // may be overriden by derived classes. 533 534 // The functionality here is only to 535 // support those people that don't 536 // use the roster to set the run mode 537 fRunMode = mode; 538 } 539 540 541 void 542 BMediaNode::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 543 { 544 CALLED(); 545 // May be overriden by derived classes. 546 } 547 548 549 void 550 BMediaNode::Preroll() 551 { 552 CALLED(); 553 // May be overriden by derived classes. 554 } 555 556 557 void 558 BMediaNode::SetTimeSource(BTimeSource* time_source) 559 { 560 CALLED(); 561 // This is a hook function, and 562 // may be overriden by derived classes. 563 564 if (time_source == NULL || time_source == fTimeSource) 565 return; 566 567 // We just trip into debugger, code that tries to do this is broken. 568 debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, " 569 "use BMediaRoster::SetTimeSourceFor()!\n"); 570 } 571 572 573 status_t 574 BMediaNode::HandleMessage(int32 message, const void* data, size_t size) 575 { 576 TRACE("BMediaNode::HandleMessage %#lx, node %ld\n", message, fNodeID); 577 switch (message) { 578 case NODE_FINAL_RELEASE: 579 { 580 TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", 581 this); 582 583 // This is called by the media server to delete the object 584 // after is has been released by all nodes that are using it. 585 // We forward the function to the BMediaRoster, since the 586 // deletion must be done from a different thread, or the 587 // outermost destructor that will exit the thread that is 588 // reading messages from the port (this thread contex) will 589 // quit, and ~BMediaNode destructor won't be called ever. 590 BMessage msg(NODE_FINAL_RELEASE); 591 msg.AddPointer("node", this); 592 BMediaRoster::Roster()->PostMessage(&msg); 593 return B_OK; 594 } 595 596 case NODE_START: 597 { 598 const node_start_command* command 599 = static_cast<const node_start_command*>(data); 600 TRACE("BMediaNode::HandleMessage NODE_START, node %ld\n", fNodeID); 601 Start(command->performance_time); 602 return B_OK; 603 } 604 605 case NODE_STOP: 606 { 607 const node_stop_command* command 608 = static_cast<const node_stop_command*>(data); 609 TRACE("BMediaNode::HandleMessage NODE_STOP, node %ld\n", fNodeID); 610 Stop(command->performance_time, command->immediate); 611 return B_OK; 612 } 613 614 case NODE_SEEK: 615 { 616 const node_seek_command* command 617 = static_cast<const node_seek_command*>(data); 618 TRACE("BMediaNode::HandleMessage NODE_SEEK, node %ld\n", fNodeID); 619 Seek(command->media_time, command->performance_time); 620 return B_OK; 621 } 622 623 case NODE_SET_RUN_MODE: 624 { 625 const node_set_run_mode_command* command 626 = static_cast<const node_set_run_mode_command*>(data); 627 TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE," 628 " node %ld\n", fNodeID); 629 // Need to change PRODUCER_SET_RUN_MODE_DELAY 630 fRunMode = command->mode; 631 SetRunMode(fRunMode); 632 return B_OK; 633 } 634 635 case NODE_TIME_WARP: 636 { 637 const node_time_warp_command* command 638 = static_cast<const node_time_warp_command*>(data); 639 TRACE("BMediaNode::HandleMessage NODE_TIME_WARP," 640 " node %ld\n", fNodeID); 641 TimeWarp(command->at_real_time, command->to_performance_time); 642 return B_OK; 643 } 644 645 case NODE_PREROLL: 646 { 647 TRACE("BMediaNode::HandleMessage NODE_PREROLL, " 648 " node %ld\n", fNodeID); 649 Preroll(); 650 return B_OK; 651 } 652 653 case NODE_ROLL: 654 { 655 const node_roll_command* command 656 = static_cast<const node_roll_command*>(data); 657 658 TRACE("BMediaNode::HandleMessage NODE_ROLL, node %ld\n", 659 fNodeID); 660 661 if (command->seek_media_time != B_INFINITE_TIMEOUT) 662 Seek(command->seek_media_time, 663 command->start_performance_time); 664 665 Start(command->start_performance_time); 666 Stop(command->stop_performance_time, false); 667 return B_OK; 668 } 669 670 case NODE_SYNC_TO: 671 { 672 const node_sync_to_request* request 673 = static_cast<const node_sync_to_request*>(data); 674 node_sync_to_reply reply; 675 676 TRACE("BMediaNode::HandleMessage NODE_SYNC_TO, node %ld\n", 677 fNodeID); 678 679 // If AddTimer return an error the caller will know that the node 680 // doesn't support this feature or there was a problem when adding 681 // it, this will result in SyncToNode returning immediately 682 // to the caller with an error. 683 status_t status = AddTimer(request->performance_time, 684 request->port); 685 686 request->SendReply(status, &reply, sizeof(reply)); 687 return B_OK; 688 } 689 690 case NODE_SET_TIMESOURCE: 691 { 692 const node_set_timesource_command* command 693 = static_cast<const node_set_timesource_command*>(data); 694 695 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE," 696 " node %ld, timesource %ld enter\n", 697 fNodeID, command->timesource_id); 698 699 fTimeSourceID = command->timesource_id; 700 701 if (fTimeSource) { 702 // As this node already had a timesource, to remove this node 703 // from time source control 704 fTimeSource->RemoveMe(this); 705 // Release the time source 706 fTimeSource->Release(); 707 // Force next call to TimeSource() to create a new object 708 fTimeSource = 0; 709 } 710 711 // Create new time source object and call the SetTimeSource 712 // hook function to notify any derived class 713 fTimeSource = TimeSource(); 714 SetTimeSource(fTimeSource); 715 716 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %ld," 717 "timesource %ld leave\n", fNodeID, command->timesource_id); 718 719 return B_OK; 720 } 721 722 case NODE_GET_TIMESOURCE: 723 { 724 const node_get_timesource_request* request 725 = static_cast<const node_get_timesource_request*>(data); 726 727 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE," 728 " node %ld\n", fNodeID); 729 730 node_get_timesource_reply reply; 731 reply.timesource_id = fTimeSourceID; 732 request->SendReply(B_OK, &reply, sizeof(reply)); 733 return B_OK; 734 } 735 736 case NODE_GET_ATTRIBUTES_FOR: 737 { 738 const node_get_attributes_for_request *request = 739 (const node_get_attributes_for_request*) data; 740 741 TRACE("BMediaNode::HandleMessage NODE_GET_ATTRIBUTES_FOR," 742 "node %ld\n", fNodeID); 743 744 node_get_attributes_for_reply reply; 745 746 media_node_attribute* addr; 747 area_id dataArea = clone_area("client attributes area", 748 (void**)&addr, B_ANY_ADDRESS, B_WRITE_AREA, 749 request->area); 750 751 if (dataArea < 0) { 752 ERROR("NODE_GET_ATTRIBUTES_FOR can't clone area\n"); 753 return B_NO_MEMORY; 754 } 755 756 status_t status = GetNodeAttributes(addr, request->count); 757 if (status == B_OK) { 758 // NOTE: we do it because there's not an easy way 759 // to guess the number of attributes filled. 760 size_t i; 761 for (i = 0; i < request->count; i++) { 762 if (addr[i].what <= 0) 763 break; 764 } 765 reply.filled_count = i; 766 } 767 request->SendReply(status, &reply, sizeof(reply)); 768 delete_area(dataArea); 769 return B_OK; 770 } 771 772 case NODE_REQUEST_COMPLETED: 773 { 774 const node_request_completed_command* command 775 = static_cast<const node_request_completed_command*>(data); 776 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED," 777 " node %ld\n", fNodeID); 778 RequestCompleted(command->info); 779 return B_OK; 780 } 781 782 default: 783 return B_ERROR; 784 785 } 786 return B_ERROR; 787 } 788 789 790 void 791 BMediaNode::HandleBadMessage(int32 code, const void* buffer, size_t size) 792 { 793 CALLED(); 794 795 TRACE("BMediaNode::HandleBadMessage: code %#08lx, buffer %p, size %ld\n", 796 code, buffer, size); 797 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 798 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 799 } else { 800 // All messages targeted to nodes should be handled here, 801 // messages targetted to the wrong node should be handled 802 // by returning an error, not by stalling the sender. 803 const request_data* request = static_cast<const request_data* >(buffer); 804 reply_data reply; 805 request->SendReply(B_ERROR, &reply, sizeof(reply)); 806 } 807 } 808 809 810 void 811 BMediaNode::AddNodeKind(uint64 kind) 812 { 813 TRACE("BMediaNode::AddNodeKind: node %ld, this %p\n", fNodeID, this); 814 fKinds |= kind; 815 } 816 817 818 void* 819 BMediaNode::operator new(size_t size) 820 { 821 CALLED(); 822 return ::operator new(size); 823 } 824 825 826 void* 827 BMediaNode::operator new(size_t size, const nothrow_t&) throw() 828 { 829 CALLED(); 830 return ::operator new(size, nothrow); 831 } 832 833 834 void 835 BMediaNode::operator delete(void* ptr) 836 { 837 CALLED(); 838 ::operator delete(ptr); 839 } 840 841 842 void 843 BMediaNode::operator delete(void* ptr, const nothrow_t&) throw() 844 { 845 CALLED(); 846 ::operator delete(ptr, nothrow); 847 } 848 849 850 status_t 851 BMediaNode::RequestCompleted(const media_request_info& info) 852 { 853 CALLED(); 854 // This function is called whenever 855 // a request issued by the node is completed. 856 // May be overriden by derived classes. 857 // info.change_tag can be used to match up requests against 858 // the accompaning calles from 859 // BBufferConsumer::RequestFormatChange() 860 // BBufferConsumer::SetOutputBuffersFor() 861 // BBufferConsumer::SetOutputEnabled() 862 // BBufferConsumer::SetVideoClippingFor() 863 return B_OK; 864 } 865 866 867 status_t 868 BMediaNode::DeleteHook(BMediaNode* node) 869 { 870 CALLED(); 871 // Attention! We do not unregister TimeSourceObject nodes, 872 // since they are only a shadow object, and the real one still exists 873 if ((fKinds & NODE_KIND_SHADOW_TIMESOURCE) == 0) 874 BMediaRoster::Roster()->UnregisterNode(this); 875 delete this; // delete "this" or "node", both are the same 876 return B_OK; 877 } 878 879 880 void 881 BMediaNode::NodeRegistered() 882 { 883 CALLED(); 884 // The Media Server calls this hook function 885 // after the node has been registered. 886 // May be overriden by derived classes. 887 } 888 889 890 status_t 891 BMediaNode::GetNodeAttributes(media_node_attribute* outAttributes, 892 size_t inMaxCount) 893 { 894 CALLED(); 895 // This is implemented by derived classes that fills 896 // it's own attributes to a max of inMaxCount elements. 897 return B_ERROR; 898 } 899 900 901 status_t 902 BMediaNode::AddTimer(bigtime_t at_performance_time, int32 cookie) 903 { 904 CALLED(); 905 return B_ERROR; 906 } 907 908 909 status_t BMediaNode::_Reserved_MediaNode_0(void*) { return B_ERROR; } 910 status_t BMediaNode::_Reserved_MediaNode_1(void*) { return B_ERROR; } 911 status_t BMediaNode::_Reserved_MediaNode_2(void*) { return B_ERROR; } 912 status_t BMediaNode::_Reserved_MediaNode_3(void*) { return B_ERROR; } 913 status_t BMediaNode::_Reserved_MediaNode_4(void*) { return B_ERROR; } 914 status_t BMediaNode::_Reserved_MediaNode_5(void*) { return B_ERROR; } 915 status_t BMediaNode::_Reserved_MediaNode_6(void*) { return B_ERROR; } 916 status_t BMediaNode::_Reserved_MediaNode_7(void*) { return B_ERROR; } 917 status_t BMediaNode::_Reserved_MediaNode_8(void*) { return B_ERROR; } 918 status_t BMediaNode::_Reserved_MediaNode_9(void*) { return B_ERROR; } 919 status_t BMediaNode::_Reserved_MediaNode_10(void*) { return B_ERROR; } 920 status_t BMediaNode::_Reserved_MediaNode_11(void*) { return B_ERROR; } 921 status_t BMediaNode::_Reserved_MediaNode_12(void*) { return B_ERROR; } 922 status_t BMediaNode::_Reserved_MediaNode_13(void*) { return B_ERROR; } 923 status_t BMediaNode::_Reserved_MediaNode_14(void*) { return B_ERROR; } 924 status_t BMediaNode::_Reserved_MediaNode_15(void*) { return B_ERROR; } 925 926 /* 927 private unimplemented 928 BMediaNode::BMediaNode() 929 BMediaNode::BMediaNode(const BMediaNode &clone) 930 BMediaNode &BMediaNode::operator=(const BMediaNode &clone) 931 */ 932 933 void 934 BMediaNode::_InitObject(const char* name, media_node_id id, uint64 kinds) 935 { 936 TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); 937 938 fNodeID = id; 939 fRefCount = 1; 940 fName[0] = 0; 941 if (name) 942 strlcpy(fName, name, B_MEDIA_NAME_LENGTH); 943 fRunMode = B_INCREASE_LATENCY; 944 fKinds = kinds; 945 fProducerThis = 0; 946 fConsumerThis = 0; 947 fFileInterfaceThis = 0; 948 fControllableThis = 0; 949 fTimeSourceThis = 0; 950 951 // Create control port 952 fControlPort = create_port(64, fName); 953 954 // Nodes are assigned the system time source by default 955 fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; 956 957 // We can't create the timesource object here, because 958 // every timesource is a BMediaNode, which would result 959 // in infinite recursions 960 fTimeSource = NULL; 961 } 962 963 964 BMediaNode::BMediaNode(const char* name, media_node_id id, uint32 kinds) 965 { 966 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %ld, kinds %#lx\n", 967 name, id, kinds); 968 _InitObject(name, id, kinds); 969 } 970 971 972 int32 973 BMediaNode::NewChangeTag() 974 { 975 CALLED(); 976 // Change tags have been used in BeOS R4 to match up 977 // format change requests between producer and consumer, 978 // This has changed starting with R4.5 979 // now "change tags" are used with the following functions: 980 // BMediaNode::RequestCompleted() 981 // BBufferConsumer::RequestFormatChange() 982 // BBufferConsumer::SetOutputBuffersFor() 983 // BBufferConsumer::SetOutputEnabled() 984 // BBufferConsumer::SetVideoClippingFor() 985 return atomic_add(&BMediaNode::_m_changeTag,1); 986 } 987 988 // BeOS R4 deprecated API 989 990 int32 991 BMediaNode::IncrementChangeTag() 992 { 993 CALLED(); 994 // Only present in BeOS R4 995 // Obsoleted in BeOS R4.5 and later 996 // "updates the change tag, so that downstream consumers 997 // know that the node is in a new state." 998 // not supported, only for binary compatibility 999 return 0; 1000 } 1001 1002 1003 int32 1004 BMediaNode::ChangeTag() 1005 { 1006 UNIMPLEMENTED(); 1007 // Only present in BeOS R4 1008 // Obsoleted in BeOS R4.5 and later 1009 // "returns the node's current change tag value." 1010 // not supported, only for binary compatibility 1011 return 0; 1012 } 1013 1014 1015 int32 1016 BMediaNode::MintChangeTag() 1017 { 1018 UNIMPLEMENTED(); 1019 // Only present in BeOS R4 1020 // Obsoleted in BeOS R4.5 and later 1021 // "mints a new, reserved, change tag." 1022 // "Call ApplyChangeTag() to apply it to the node" 1023 // not supported, only for binary compatibility 1024 return 0; 1025 } 1026 1027 1028 status_t 1029 BMediaNode::ApplyChangeTag(int32 previously_reserved) 1030 { 1031 UNIMPLEMENTED(); 1032 // Only present in BeOS R4 1033 // Obsoleted in BeOS R4.5 and later 1034 // "this returns B_OK if the new change tag is" 1035 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 1036 // "count you tried to apply is already obsolete." 1037 // not supported, only for binary compatibility 1038 return B_OK; 1039 } 1040