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 const 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 %" B_PRId32 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 %" B_PRId32 " 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 %" B_PRId32 " 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: %#" B_PRIx32 ", node %" 385 B_PRId32 ", this %p\n", 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 %#" B_PRIx32", node %" B_PRId32 "\n", 571 message, fNodeID); 572 switch (message) { 573 case NODE_FINAL_RELEASE: 574 { 575 TRACE("BMediaNode::HandleMessage NODE_FINAL_RELEASE, this %p\n", 576 this); 577 578 // This is called by the media server to delete the object 579 // after is has been released by all nodes that are using it. 580 // We forward the function to the BMediaRoster, since the 581 // deletion must be done from a different thread, or the 582 // outermost destructor that will exit the thread that is 583 // reading messages from the port (this thread contex) will 584 // quit, and ~BMediaNode destructor won't be called ever. 585 BMessage msg(NODE_FINAL_RELEASE); 586 msg.AddPointer("node", this); 587 BMediaRoster::Roster()->PostMessage(&msg); 588 return B_OK; 589 } 590 591 case NODE_START: 592 { 593 const node_start_command* command 594 = static_cast<const node_start_command*>(data); 595 TRACE("BMediaNode::HandleMessage NODE_START, node %" B_PRId32 "\n", 596 fNodeID); 597 Start(command->performance_time); 598 return B_OK; 599 } 600 601 case NODE_STOP: 602 { 603 const node_stop_command* command 604 = static_cast<const node_stop_command*>(data); 605 TRACE("BMediaNode::HandleMessage NODE_STOP, node %" B_PRId32 "\n", 606 fNodeID); 607 Stop(command->performance_time, command->immediate); 608 return B_OK; 609 } 610 611 case NODE_SEEK: 612 { 613 const node_seek_command* command 614 = static_cast<const node_seek_command*>(data); 615 TRACE("BMediaNode::HandleMessage NODE_SEEK, node %" B_PRId32 "\n", 616 fNodeID); 617 Seek(command->media_time, command->performance_time); 618 return B_OK; 619 } 620 621 case NODE_SET_RUN_MODE: 622 { 623 const node_set_run_mode_command* command 624 = static_cast<const node_set_run_mode_command*>(data); 625 TRACE("BMediaNode::HandleMessage NODE_SET_RUN_MODE," 626 " node %" B_PRId32 "\n", fNodeID); 627 // Need to change PRODUCER_SET_RUN_MODE_DELAY 628 fRunMode = command->mode; 629 SetRunMode(fRunMode); 630 return B_OK; 631 } 632 633 case NODE_TIME_WARP: 634 { 635 const node_time_warp_command* command 636 = static_cast<const node_time_warp_command*>(data); 637 TRACE("BMediaNode::HandleMessage NODE_TIME_WARP," 638 " node %" B_PRId32 "\n", fNodeID); 639 TimeWarp(command->at_real_time, command->to_performance_time); 640 return B_OK; 641 } 642 643 case NODE_PREROLL: 644 { 645 TRACE("BMediaNode::HandleMessage NODE_PREROLL, " 646 " node %" B_PRId32 "\n", fNodeID); 647 Preroll(); 648 return B_OK; 649 } 650 651 case NODE_ROLL: 652 { 653 const node_roll_command* command 654 = static_cast<const node_roll_command*>(data); 655 656 TRACE("BMediaNode::HandleMessage NODE_ROLL, node %" B_PRId32 "\n", 657 fNodeID); 658 659 if (command->seek_media_time != B_INFINITE_TIMEOUT) 660 Seek(command->seek_media_time, 661 command->start_performance_time); 662 663 Start(command->start_performance_time); 664 Stop(command->stop_performance_time, false); 665 return B_OK; 666 } 667 668 case NODE_SYNC_TO: 669 { 670 const node_sync_to_request* request 671 = static_cast<const node_sync_to_request*>(data); 672 node_sync_to_reply reply; 673 674 TRACE("BMediaNode::HandleMessage NODE_SYNC_TO, node %" B_PRId32 675 "\n", fNodeID); 676 677 // If AddTimer return an error the caller will know that the node 678 // doesn't support this feature or there was a problem when adding 679 // it, this will result in SyncToNode returning immediately 680 // to the caller with an error. 681 status_t status = AddTimer(request->performance_time, 682 request->port); 683 684 request->SendReply(status, &reply, sizeof(reply)); 685 return B_OK; 686 } 687 688 case NODE_SET_TIMESOURCE: 689 { 690 const node_set_timesource_command* command 691 = static_cast<const node_set_timesource_command*>(data); 692 693 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE," 694 " node %" B_PRId32 ", timesource %" B_PRId32 " enter\n", 695 fNodeID, command->timesource_id); 696 697 fTimeSourceID = command->timesource_id; 698 699 if (fTimeSource) { 700 // As this node already had a timesource, to remove this node 701 // from time source control 702 fTimeSource->RemoveMe(this); 703 // Release the time source 704 fTimeSource->Release(); 705 // Force next call to TimeSource() to create a new object 706 fTimeSource = 0; 707 } 708 709 // Create new time source object and call the SetTimeSource 710 // hook function to notify any derived class 711 fTimeSource = TimeSource(); 712 SetTimeSource(fTimeSource); 713 714 TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE, node %" 715 B_PRId32 ", timesource %" B_PRId32 " leave\n", fNodeID, 716 command->timesource_id); 717 718 return B_OK; 719 } 720 721 case NODE_GET_TIMESOURCE: 722 { 723 const node_get_timesource_request* request 724 = static_cast<const node_get_timesource_request*>(data); 725 726 TRACE("BMediaNode::HandleMessage NODE_GET_TIMESOURCE," 727 " node %" B_PRId32 "\n", fNodeID); 728 729 node_get_timesource_reply reply; 730 reply.timesource_id = fTimeSourceID; 731 request->SendReply(B_OK, &reply, sizeof(reply)); 732 return B_OK; 733 } 734 735 case NODE_GET_ATTRIBUTES_FOR: 736 { 737 const node_get_attributes_for_request *request = 738 (const node_get_attributes_for_request*) data; 739 740 TRACE("BMediaNode::HandleMessage NODE_GET_ATTRIBUTES_FOR," 741 "node %" B_PRId32 "\n", fNodeID); 742 743 node_get_attributes_for_reply reply; 744 745 media_node_attribute* addr; 746 area_id dataArea = clone_area("client attributes area", 747 (void**)&addr, B_ANY_ADDRESS, B_WRITE_AREA, 748 request->area); 749 750 if (dataArea < 0) { 751 ERROR("NODE_GET_ATTRIBUTES_FOR can't clone area\n"); 752 return B_NO_MEMORY; 753 } 754 755 status_t status = GetNodeAttributes(addr, request->count); 756 if (status == B_OK) { 757 // NOTE: we do it because there's not an easy way 758 // to guess the number of attributes filled. 759 size_t i; 760 for (i = 0; i < request->count; i++) { 761 if (addr[i].what <= 0) 762 break; 763 } 764 reply.filled_count = i; 765 } 766 request->SendReply(status, &reply, sizeof(reply)); 767 delete_area(dataArea); 768 return B_OK; 769 } 770 771 case NODE_REQUEST_COMPLETED: 772 { 773 const node_request_completed_command* command 774 = static_cast<const node_request_completed_command*>(data); 775 TRACE("BMediaNode::HandleMessage NODE_REQUEST_COMPLETED," 776 " node %" B_PRId32 "\n", fNodeID); 777 RequestCompleted(command->info); 778 return B_OK; 779 } 780 781 default: 782 return B_ERROR; 783 784 } 785 return B_ERROR; 786 } 787 788 789 void 790 BMediaNode::HandleBadMessage(int32 code, const void* buffer, size_t size) 791 { 792 CALLED(); 793 794 TRACE("BMediaNode::HandleBadMessage: code %#08" B_PRIx32 ", buffer %p, size %" 795 B_PRIuSIZE "\n", code, buffer, size); 796 if (code < NODE_MESSAGE_START || code > TIMESOURCE_MESSAGE_END) { 797 ERROR("BMediaNode::HandleBadMessage: unknown code!\n"); 798 } else { 799 // All messages targeted to nodes should be handled here, 800 // messages targetted to the wrong node should be handled 801 // by returning an error, not by stalling the sender. 802 const request_data* request = static_cast<const request_data* >(buffer); 803 reply_data reply; 804 request->SendReply(B_ERROR, &reply, sizeof(reply)); 805 } 806 } 807 808 809 void 810 BMediaNode::AddNodeKind(uint64 kind) 811 { 812 TRACE("BMediaNode::AddNodeKind: node %" B_PRId32 ", this %p\n", fNodeID, 813 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 %" B_PRId32 ", this %p\n", id, 937 this); 938 939 fNodeID = id; 940 fRefCount = 1; 941 fName[0] = 0; 942 if (name) 943 strlcpy(fName, name, B_MEDIA_NAME_LENGTH); 944 fRunMode = B_INCREASE_LATENCY; 945 fKinds = kinds; 946 fProducerThis = 0; 947 fConsumerThis = 0; 948 fFileInterfaceThis = 0; 949 fControllableThis = 0; 950 fTimeSourceThis = 0; 951 952 // Create control port 953 fControlPort = create_port(64, fName); 954 955 // Nodes are assigned the system time source by default 956 fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; 957 958 // We can't create the timesource object here, because 959 // every timesource is a BMediaNode, which would result 960 // in infinite recursions 961 fTimeSource = NULL; 962 } 963 964 965 BMediaNode::BMediaNode(const char* name, media_node_id id, uint32 kinds) 966 { 967 TRACE("BMediaNode::BMediaNode: name '%s', nodeid %" B_PRId32 ", kinds %#" 968 B_PRIx32 "\n", name, id, kinds); 969 _InitObject(name, id, kinds); 970 } 971 972 973 int32 974 BMediaNode::NewChangeTag() 975 { 976 CALLED(); 977 // Change tags have been used in BeOS R4 to match up 978 // format change requests between producer and consumer, 979 // This has changed starting with R4.5 980 // now "change tags" are used with the following functions: 981 // BMediaNode::RequestCompleted() 982 // BBufferConsumer::RequestFormatChange() 983 // BBufferConsumer::SetOutputBuffersFor() 984 // BBufferConsumer::SetOutputEnabled() 985 // BBufferConsumer::SetVideoClippingFor() 986 return atomic_add(&BMediaNode::_m_changeTag,1); 987 } 988 989 // BeOS R4 deprecated API 990 991 int32 992 BMediaNode::IncrementChangeTag() 993 { 994 CALLED(); 995 // Only present in BeOS R4 996 // Obsoleted in BeOS R4.5 and later 997 // "updates the change tag, so that downstream consumers 998 // know that the node is in a new state." 999 // not supported, only for binary compatibility 1000 return 0; 1001 } 1002 1003 1004 int32 1005 BMediaNode::ChangeTag() 1006 { 1007 UNIMPLEMENTED(); 1008 // Only present in BeOS R4 1009 // Obsoleted in BeOS R4.5 and later 1010 // "returns the node's current change tag value." 1011 // not supported, only for binary compatibility 1012 return 0; 1013 } 1014 1015 1016 int32 1017 BMediaNode::MintChangeTag() 1018 { 1019 UNIMPLEMENTED(); 1020 // Only present in BeOS R4 1021 // Obsoleted in BeOS R4.5 and later 1022 // "mints a new, reserved, change tag." 1023 // "Call ApplyChangeTag() to apply it to the node" 1024 // not supported, only for binary compatibility 1025 return 0; 1026 } 1027 1028 1029 status_t 1030 BMediaNode::ApplyChangeTag(int32 previously_reserved) 1031 { 1032 UNIMPLEMENTED(); 1033 // Only present in BeOS R4 1034 // Obsoleted in BeOS R4.5 and later 1035 // "this returns B_OK if the new change tag is" 1036 // "successfully applied, or B_MEDIA_STALE_CHANGE_TAG if the new change" 1037 // "count you tried to apply is already obsolete." 1038 // not supported, only for binary compatibility 1039 return B_OK; 1040 } 1041