1 /* 2 * Copyright 1991-1999, Be Incorporated. 3 * Copyright (c) 1999-2000, Eric Moon. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions, and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions, and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 // LoggingConsumer.cpp 34 35 #include "LoggingConsumer.h" 36 #include "LogWriter.h" 37 #include <media/MediaRoster.h> 38 #include <media/TimeSource.h> 39 #include <media/ParameterWeb.h> 40 #include <media/Buffer.h> 41 #include <kernel/OS.h> 42 #include <stdio.h> 43 #include <string.h> 44 45 // e.moon [11jun99] 46 #include <Debug.h> 47 48 // id's of the node's BParameters 49 const int32 INPUT_NULL_PARAM = 1; 50 const int32 LATENCY_PARAM = 2; 51 const int32 OUTPUT_NULL_PARAM = 3; 52 const int32 CPU_NULL_PARAM = 11; 53 const int32 CPU_SPIN_PARAM = 12; 54 const int32 PRIO_NULL_PARAM = 21; 55 const int32 PRIORITY_PARAM = 22; 56 57 // build the LoggingConsumer's BParameterWeb 58 static BParameterWeb* build_parameter_web() 59 { 60 BParameterWeb* web = new BParameterWeb; 61 62 BParameterGroup* mainGroup = web->MakeGroup("LoggingConsumer Parameters"); 63 BParameterGroup* group = mainGroup->MakeGroup("Latency control"); 64 BParameter* nullParam = group->MakeNullParameter(INPUT_NULL_PARAM, B_MEDIA_NO_TYPE, "Latency", B_GENERIC); 65 BParameter* latencyParam = group->MakeContinuousParameter(LATENCY_PARAM, B_MEDIA_NO_TYPE, "", 66 B_GAIN, "ms", 5, 100, 5); 67 nullParam->AddOutput(latencyParam); 68 latencyParam->AddInput(nullParam); 69 70 group = mainGroup->MakeGroup("CPU percentage"); 71 nullParam = group->MakeNullParameter(CPU_NULL_PARAM, B_MEDIA_NO_TYPE, "CPU spin percentage", B_GENERIC); 72 BContinuousParameter* cpuParam = group->MakeContinuousParameter(CPU_SPIN_PARAM, B_MEDIA_NO_TYPE, "", 73 B_GAIN, "percent", 5, 80, 5); 74 nullParam->AddOutput(cpuParam); 75 cpuParam->AddInput(nullParam); 76 77 group = mainGroup->MakeGroup("Priority"); 78 nullParam = group->MakeNullParameter(PRIO_NULL_PARAM, B_MEDIA_NO_TYPE, "Thread priority", B_GENERIC); 79 BDiscreteParameter* prioParam = group->MakeDiscreteParameter(PRIORITY_PARAM, B_MEDIA_NO_TYPE, "", B_GENERIC); 80 prioParam->AddItem(5, "B_LOW_PRIORITY"); 81 prioParam->AddItem(10, "B_NORMAL_PRIORITY"); 82 prioParam->AddItem(15, "B_DISPLAY_PRIORITY"); 83 prioParam->AddItem(20, "B_URGENT_DISPLAY_PRIORITY"); 84 prioParam->AddItem(100, "B_REAL_TIME_DISPLAY_PRIORITY"); 85 prioParam->AddItem(110, "B_URGENT_PRIORITY"); 86 prioParam->AddItem(120, "B_REAL_TIME_PRIORITY"); 87 88 return web; 89 } 90 91 // -------------------- 92 // LoggingConsumer class implementation 93 LoggingConsumer::LoggingConsumer( 94 const entry_ref& logFile, 95 BMediaAddOn* pAddOn) 96 97 : BMediaNode("LoggingConsumer"), 98 BBufferConsumer(B_MEDIA_UNKNOWN_TYPE), 99 BControllable(), 100 BMediaEventLooper(), 101 mLogRef(logFile), 102 mWeb(NULL), 103 mLateBuffers(0), 104 mLatency(50 * 1000), // default to 50 milliseconds 105 mSpinPercentage(0.10), // default to spinning 10% of total latency 106 mPriority(B_URGENT_DISPLAY_PRIORITY), // !!! testing; will be B_REAL_TIME_PRIORITY for release 107 mLastLatencyChange(0), 108 mLastSpinChange(0), 109 mLastPrioChange(0), 110 m_pAddOn(pAddOn) 111 { 112 // spin off the logging thread 113 mLogger = new LogWriter(logFile); 114 115 // parameter-web init moved to NodeRegistered() 116 // e.moon [11jun99] 117 } 118 119 LoggingConsumer::~LoggingConsumer() 120 { 121 PRINT(("~LoggingConsumer()\n")); 122 BMediaEventLooper::Quit(); 123 // ahem: 124 // "Once you've called BControllable::SetParameterWeb(), the node takes 125 // responsibility for the parameter web object and you shouldn't delete it. " 126 // SetParameterWeb(NULL); 127 // delete mWeb; 128 129 // delete the logging thread only after the looper thread has quit, otherwise there's 130 // a potential race condition with the looper thread trying to write to the now- 131 // deleted log 132 delete mLogger; 133 } 134 135 // 136 // Log message filtering control 137 // 138 139 void 140 LoggingConsumer::SetEnabled(log_what what, bool enable) 141 { 142 mLogger->SetEnabled(what, enable); 143 } 144 145 void 146 LoggingConsumer::EnableAllMessages() 147 { 148 mLogger->EnableAllMessages(); 149 } 150 151 void 152 LoggingConsumer::DisableAllMessages() 153 { 154 mLogger->DisableAllMessages(); 155 } 156 157 // 158 // BMediaNode methods 159 // 160 161 162 BMediaAddOn* 163 LoggingConsumer::AddOn(int32 *internal_id) const 164 { 165 PRINT(("~LoggingConsumer::AddOn()\n")); 166 // e.moon [11jun99] 167 if(m_pAddOn) { 168 *internal_id = 0; 169 return m_pAddOn; 170 } else 171 return NULL; 172 } 173 174 void 175 LoggingConsumer::SetRunMode(run_mode mode) 176 { 177 // !!! Need to handle offline mode etc. properly! 178 log_message logMsg; 179 logMsg.now = TimeSource()->Now(); 180 mLogger->Log(LOG_SET_RUN_MODE, logMsg); 181 182 BMediaEventLooper::SetRunMode(mode); 183 } 184 185 void 186 LoggingConsumer::Preroll() 187 { 188 log_message logMsg; 189 logMsg.now = TimeSource()->Now(); 190 mLogger->Log(LOG_PREROLL, logMsg); 191 192 BMediaEventLooper::Preroll(); 193 } 194 195 void 196 LoggingConsumer::SetTimeSource(BTimeSource* time_source) 197 { 198 log_message logMsg; 199 logMsg.now = TimeSource()->Now(); 200 mLogger->Log(LOG_SET_TIME_SOURCE, logMsg); 201 202 BMediaNode::SetTimeSource(time_source); 203 } 204 205 status_t 206 LoggingConsumer::RequestCompleted(const media_request_info &info) 207 { 208 log_message logMsg; 209 logMsg.now = TimeSource()->Now(); 210 mLogger->Log(LOG_REQUEST_COMPLETED, logMsg); 211 212 return BMediaNode::RequestCompleted(info); 213 } 214 215 // e.moon [11jun99; testing add-on] 216 status_t 217 LoggingConsumer::DeleteHook(BMediaNode* pNode) { 218 PRINT(("LoggingConsumer::DeleteHook(%p)\n", pNode)); 219 return BBufferConsumer::DeleteHook(pNode); 220 // ASSERT(pNode == this); 221 // delete this; 222 // return B_OK; 223 } 224 225 // 226 // BControllable methods 227 // 228 229 status_t 230 LoggingConsumer::GetParameterValue(int32 id, bigtime_t* last_change, void* value, size_t* ioSize) 231 { 232 log_message logMsg; 233 logMsg.now = TimeSource()->Now(); 234 logMsg.param.id = id; 235 mLogger->Log(LOG_GET_PARAM_VALUE, logMsg); 236 237 // return an error if the caller hasn't reserved enough space for the parameter data. 238 // we know that all of our parameters fit in a float or int32 (4 bytes), so we can just 239 // check for it once here, instead of on a per-parameter basis 240 if (*ioSize < sizeof(float)) return B_ERROR; 241 242 // write out the designated parameter data 243 switch (id) 244 { 245 case LATENCY_PARAM: 246 *last_change = mLastLatencyChange; 247 *((float*) value) = mLatency / 1000; // the BParameter reads milliseconds, not microseconds 248 *ioSize = sizeof(float); 249 break; 250 251 case CPU_SPIN_PARAM: 252 *last_change = mLastSpinChange; 253 *((float*) value) = mSpinPercentage; 254 *ioSize = sizeof(float); 255 break; 256 257 case PRIORITY_PARAM: 258 *last_change = mLastPrioChange; 259 *((int32*) value) = mPriority; 260 *ioSize = sizeof(int32); 261 break; 262 263 default: 264 return B_ERROR; 265 } 266 267 return B_OK; 268 } 269 270 void 271 LoggingConsumer::SetParameterValue(int32 id, bigtime_t performance_time, const void* value, size_t size) 272 { 273 log_message logMsg; 274 logMsg.now = TimeSource()->Now(); 275 logMsg.param.id = id; 276 mLogger->Log(LOG_SET_PARAM_VALUE, logMsg); 277 278 // if it's one of our parameters, enqueue a "set parameter" event for handling at the appropriate time 279 switch (id) 280 { 281 case LATENCY_PARAM: 282 case CPU_SPIN_PARAM: 283 case PRIORITY_PARAM: 284 { 285 // !!! Change from B_USER_EVENT to B_SET_PARAMETER once it's defined 286 media_timed_event event(performance_time, BTimedEventQueue::B_USER_EVENT, 287 (void*) value, BTimedEventQueue::B_NO_CLEANUP, size, id, NULL); 288 EventQueue()->AddEvent(event); 289 } 290 break; 291 292 default: // do nothing for other parameter IDs 293 break; 294 } 295 return; 296 } 297 298 // 299 // BBufferConsumer methods 300 // 301 302 status_t 303 LoggingConsumer::HandleMessage(int32 message, const void *data, size_t size) 304 { 305 log_message logMsg; 306 logMsg.now = TimeSource()->Now(); 307 mLogger->Log(LOG_HANDLE_MESSAGE, logMsg); 308 309 // try each of our superclasses to handle the message 310 status_t err; 311 err = BControllable::HandleMessage(message, data, size); 312 if (err) err = BBufferConsumer::HandleMessage(message, data, size); 313 if (err) err = BMediaNode::HandleMessage(message, data, size); 314 return err; 315 } 316 317 // all of these next methods are pure virtual in BBufferConsumer 318 319 status_t 320 LoggingConsumer::AcceptFormat(const media_destination& dest, media_format* format) 321 { 322 char formatStr[256]; 323 string_for_format(*format, formatStr, 255); 324 PRINT(("LoggingConsumer::AcceptFormat:\n\tformat %s\n", formatStr)); 325 326 log_message logMsg; 327 logMsg.now = TimeSource()->Now(); 328 mLogger->Log(LOG_ACCEPT_FORMAT, logMsg); 329 330 // return an error if this isn't really our one input's destination 331 if (dest != mInput.destination) return B_MEDIA_BAD_DESTINATION; 332 333 // the destination given really is our input, and we accept any kind of media data, 334 // so now we just confirm that we can handle whatever the producer asked for. 335 return B_OK; 336 } 337 338 status_t 339 LoggingConsumer::GetNextInput(int32* cookie, media_input* out_input) 340 { 341 // we have a single hardcoded input that can accept any kind of media data 342 if (0 == *cookie) 343 { 344 mInput.format.type = B_MEDIA_UNKNOWN_TYPE; // accept any format 345 346 *out_input = mInput; 347 *cookie = 1; 348 return B_OK; 349 } 350 else return B_BAD_INDEX; 351 } 352 353 void 354 LoggingConsumer::DisposeInputCookie(int32 /*cookie*/ ) 355 { 356 // we don't use any kind of state or extra storage for iterating over our 357 // inputs, so we don't have to do any special disposal of input cookies. 358 } 359 360 void 361 LoggingConsumer::BufferReceived(BBuffer* buffer) 362 { 363 bigtime_t bufferStart = buffer->Header()->start_time; 364 bigtime_t now = TimeSource()->Now(); 365 bigtime_t how_early = bufferStart - EventLatency() - SchedulingLatency() - now; 366 367 log_message logMsg; 368 logMsg.now = now; 369 logMsg.buffer_data.start_time = bufferStart; 370 logMsg.buffer_data.offset = how_early; 371 mLogger->Log(LOG_BUFFER_RECEIVED, logMsg); 372 373 // There's a special case here with handling B_MEDIA_PARAMETERS buffers. 374 // These contain sets of parameter value changes, with their own performance 375 // times embedded in the buffers. So, we want to dispatch those parameter 376 // changes as their own events rather than pushing this buffer on the queue to 377 // be handled later. 378 if (B_MEDIA_PARAMETERS == buffer->Header()->type) 379 { 380 ApplyParameterData(buffer->Data(), buffer->SizeUsed()); 381 buffer->Recycle(); 382 } 383 else // ahh, it's a regular media buffer, so push it on the event queue 384 { 385 status_t err; 386 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 387 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 388 err = EventQueue()->AddEvent(event); 389 390 // HandleEvent() will recycle the buffer. However, if we incurred an error trying to 391 // put the event into the queue, we have to recycle it ourselves, since HandleEvent() 392 // will never see the buffer in that case. 393 if (err) buffer->Recycle(); 394 } 395 } 396 397 void 398 LoggingConsumer::ProducerDataStatus(const media_destination& for_whom, int32 status, bigtime_t at_performance_time) 399 { 400 log_message logMsg; 401 logMsg.now = TimeSource()->Now(); 402 logMsg.data_status.status = status; 403 mLogger->Log(LOG_PRODUCER_DATA_STATUS, logMsg); 404 405 if (for_whom == mInput.destination) 406 { 407 media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, 408 &mInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 409 EventQueue()->AddEvent(event); 410 } 411 } 412 413 status_t 414 LoggingConsumer::GetLatencyFor(const media_destination& for_whom, bigtime_t* out_latency, media_node_id* out_timesource) 415 { 416 // make sure this is one of my valid inputs 417 if (for_whom != mInput.destination) return B_MEDIA_BAD_DESTINATION; 418 419 // report internal latency + downstream latency here, NOT including scheduling latency. 420 // we're a final consumer (no outputs), so we have no downstream latency. 421 *out_latency = mLatency; 422 *out_timesource = TimeSource()->ID(); 423 return B_OK; 424 } 425 426 status_t 427 LoggingConsumer::Connected( 428 const media_source& producer, 429 const media_destination& where, 430 const media_format& with_format, 431 media_input* out_input) 432 { 433 434 char formatStr[256]; 435 string_for_format(with_format, formatStr, 255); 436 PRINT(("LoggingConsumer::Connected:\n\tformat %s\n", formatStr)); 437 string_for_format(mInput.format, formatStr, 255); 438 PRINT(("\tinput format %s\n", formatStr)); 439 440 log_message logMsg; 441 logMsg.now = TimeSource()->Now(); 442 mLogger->Log(LOG_CONNECTED, logMsg); 443 444 if (where != mInput.destination) return B_MEDIA_BAD_DESTINATION; 445 446 // calculate my latency here, because it may depend on buffer sizes/durations, then 447 // tell the BMediaEventLooper how early we need to get the buffers 448 SetEventLatency(mLatency); 449 450 // record useful information about the connection, and return success 451 // * e.moon [14jun99]: stores format 452 mInput.format = with_format; 453 mInput.source = producer; 454 *out_input = mInput; 455 return B_OK; 456 } 457 458 void 459 LoggingConsumer::Disconnected( 460 const media_source& producer, 461 const media_destination& where) 462 { 463 log_message logMsg; 464 logMsg.now = TimeSource()->Now(); 465 mLogger->Log(LOG_DISCONNECTED, logMsg); 466 467 // wipe out our input record 468 memset(&mInput, 0, sizeof(mInput)); 469 } 470 471 status_t 472 LoggingConsumer::FormatChanged( 473 const media_source& producer, 474 const media_destination& consumer, 475 int32 change_tag, 476 const media_format& format) 477 { 478 log_message logMsg; 479 logMsg.now = TimeSource()->Now(); 480 mLogger->Log(LOG_FORMAT_CHANGED, logMsg); 481 482 return B_OK; 483 } 484 485 status_t 486 LoggingConsumer::SeekTagRequested( 487 const media_destination& destination, 488 bigtime_t in_target_time, 489 uint32 in_flags, 490 media_seek_tag* out_seek_tag, 491 bigtime_t* out_tagged_time, 492 uint32* out_flags) 493 { 494 log_message logMsg; 495 logMsg.now = TimeSource()->Now(); 496 mLogger->Log(LOG_SEEK_TAG, logMsg); 497 498 return B_OK; 499 } 500 501 // 502 // BMediaEventLooper virtual methods 503 // 504 505 void 506 LoggingConsumer::NodeRegistered() 507 { 508 log_message logMsg; 509 logMsg.now = TimeSource()->Now(); 510 mLogger->Log(LOG_REGISTERED, logMsg); 511 512 // publish our parameter web 513 mWeb = build_parameter_web(); 514 SetParameterWeb(mWeb); 515 516 // Set our priority and start the BMediaEventLooper's thread 517 SetPriority(mPriority); 518 Run(); 519 520 // Initialize as much of our input as we can, now that the Media Kit really "knows" about us 521 mInput.destination.port = ControlPort(); 522 mInput.destination.id = 0; 523 mInput.node = Node(); 524 strcpy(mInput.name, "Logged input"); 525 } 526 527 void 528 LoggingConsumer::Start(bigtime_t performance_time) 529 { 530 PRINT(("LoggingConsumer::Start(%" B_PRIdBIGTIME "): now %" B_PRIdBIGTIME "\n", 531 performance_time, TimeSource()->Now())); 532 533 log_message logMsg; 534 logMsg.now = TimeSource()->Now(); 535 mLogger->Log(LOG_START, logMsg); 536 537 BMediaEventLooper::Start(performance_time); 538 } 539 540 void 541 LoggingConsumer::Stop(bigtime_t performance_time, bool immediate) 542 { 543 log_message logMsg; 544 logMsg.now = TimeSource()->Now(); 545 mLogger->Log(LOG_STOP, logMsg); 546 547 BMediaEventLooper::Stop(performance_time, immediate); 548 } 549 550 void 551 LoggingConsumer::Seek(bigtime_t media_time, bigtime_t performance_time) 552 { 553 log_message logMsg; 554 logMsg.now = TimeSource()->Now(); 555 mLogger->Log(LOG_SEEK, logMsg); 556 557 BMediaEventLooper::Seek(media_time, performance_time); 558 } 559 560 void 561 LoggingConsumer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 562 { 563 log_message logMsg; 564 logMsg.now = TimeSource()->Now(); 565 mLogger->Log(LOG_TIMEWARP, logMsg); 566 567 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); 568 } 569 570 void 571 LoggingConsumer::HandleEvent(const media_timed_event *event, bigtime_t /* lateness */, bool /* realTimeEvent */) 572 { 573 log_message logMsg; 574 logMsg.now = TimeSource()->Now(); 575 mLogger->Log(LOG_HANDLE_EVENT, logMsg); 576 577 switch (event->type) 578 { 579 case BTimedEventQueue::B_HANDLE_BUFFER: 580 { 581 BBuffer* buffer = const_cast<BBuffer*>((BBuffer*) event->pointer); 582 if (buffer) 583 { 584 media_header* hdr = buffer->Header(); 585 if (hdr->destination == mInput.destination.id) 586 { 587 bigtime_t now = TimeSource()->Now(); 588 bigtime_t perf_time = hdr->start_time; 589 590 // the how_early calculated here doesn't include scheduling latency because 591 // we've already been scheduled to handle the buffer 592 bigtime_t how_early = perf_time - mLatency - now; 593 594 // logMsg.now is already set 595 logMsg.buffer_data.start_time = perf_time; 596 logMsg.buffer_data.offset = how_early; 597 mLogger->Log(LOG_BUFFER_HANDLED, logMsg); 598 599 // if the buffer is late, we ignore it and report the fact to the producer 600 // who sent it to us 601 if (how_early < 0) 602 { 603 mLateBuffers++; 604 NotifyLateProducer(mInput.source, -how_early, perf_time); 605 } 606 else 607 { 608 // burn some percentage of our stated latency in CPU time (controlled by 609 // a BParameter). this simulates a user-configurable amount of CPU cost 610 // associated with the consumer. 611 bigtime_t spin_start = ::system_time(); 612 bigtime_t spin_now = spin_start; 613 bigtime_t usecToSpin = bigtime_t(mSpinPercentage / 100.0 * mLatency); 614 while (spin_now - spin_start < usecToSpin) 615 { 616 for (long k = 0; k < 1000000; k++) { /* intentionally blank */ } 617 spin_now = ::system_time(); 618 } 619 } 620 621 // we're done "processing the buffer;" now we recycle it and return to the loop 622 buffer->Recycle(); 623 } 624 else 625 { 626 //fprintf(stderr, "* Woah! Got a buffer for a different destination!\n"); 627 } 628 } 629 } 630 break; 631 632 // !!! change to B_PARAMETER as soon as it's available 633 634 // +++++ e.moon [16jun99] 635 // !!! this can't be right: the parameter value is accessed by the pointer 636 // originally passed to SetParameterValue(). there's no guarantee that 637 // value's still valid, is there? 638 639 case BTimedEventQueue::B_USER_EVENT: 640 { 641 size_t dataSize = size_t(event->data); 642 int32 param = int32(event->bigdata); 643 logMsg.param.id = param; 644 645 // handle the message if there's sufficient data provided. we only check against 646 // sizeof(float) because all of our parameters happen to be 4 bytes. if various 647 // parameters took different amounts of data, we'd check the size on a per-parameter 648 // basis. 649 if (dataSize >= sizeof(float)) switch (param) 650 { 651 case LATENCY_PARAM: 652 { 653 float value = *((float*) event->pointer); 654 mLatency = bigtime_t(value* 1000); 655 mLastLatencyChange = logMsg.now; 656 657 // my latency just changed, so reconfigure the BMediaEventLooper 658 // to give me my events at the proper time 659 SetEventLatency(mLatency); 660 661 // tell the producer that my latency changed, and broadcast a message 662 // about the parameter change to any applications that may be looking 663 // for it through the BMediaRoster::StartWatching() mechanism. 664 // 665 // if we had more than one input, we'd need to tell *all* producers about 666 // the change in our latency. 667 SendLatencyChange(mInput.source, mInput.destination, EventLatency() + SchedulingLatency()); 668 BroadcastNewParameterValue(logMsg.now, param, &value, sizeof(value)); 669 670 // log the new latency value, for recordkeeping 671 logMsg.param.value = value; 672 mLogger->Log(LOG_SET_PARAM_HANDLED, logMsg); 673 } 674 break; 675 676 case CPU_SPIN_PARAM: 677 { 678 float value = *((float*) event->pointer); 679 mSpinPercentage = value; 680 mLastSpinChange = logMsg.now; 681 BroadcastNewParameterValue(logMsg.now, param, &value, sizeof(value)); 682 logMsg.param.value = value; 683 mLogger->Log(LOG_SET_PARAM_HANDLED, logMsg); 684 } 685 break; 686 687 case PRIORITY_PARAM: 688 { 689 mPriority = *((int32*) event->pointer); 690 // DO NOT use ::set_thead_priority() to directly alter the node's control 691 // thread priority. BMediaEventLooper tracks the priority itself and recalculates 692 // the node's scheduling latency whenever SetPriority() is called. This is VERY 693 // important for correct functioning of a node chain. You should *only* alter a 694 // BMediaEventLooper's priority by calling its SetPriority() method. 695 SetPriority(mPriority); 696 697 mLastPrioChange = logMsg.now; 698 BroadcastNewParameterValue(logMsg.now, param, &mPriority, sizeof(mPriority)); 699 logMsg.param.value = (float) mPriority; 700 mLogger->Log(LOG_SET_PARAM_HANDLED, logMsg); 701 } 702 break; 703 704 // log the fact that we "handled" a "set parameter" event for a 705 // nonexistent parameter 706 default: 707 mLogger->Log(LOG_INVALID_PARAM_HANDLED, logMsg); 708 break; 709 } 710 } 711 break; 712 713 case BTimedEventQueue::B_START: 714 // okay, let's go! 715 mLogger->Log(LOG_START_HANDLED, logMsg); 716 break; 717 718 case BTimedEventQueue::B_STOP: 719 mLogger->Log(LOG_STOP_HANDLED, logMsg); 720 // stopping implies not handling any more buffers. So, we flush all pending 721 // buffers out of the event queue before returning to the event loop. 722 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 723 break; 724 725 case BTimedEventQueue::B_SEEK: 726 // seeking the log doesn't make any sense, so we just log that we handled the seek 727 // and return without doing anything else 728 mLogger->Log(LOG_SEEK_HANDLED, logMsg); 729 break; 730 731 case BTimedEventQueue::B_WARP: 732 // similarly, time warps aren't meaningful to the logger, so just record it and return 733 mLogger->Log(LOG_WARP_HANDLED, logMsg); 734 break; 735 736 case BTimedEventQueue::B_DATA_STATUS: 737 // we really don't care about the producer's data status, but this is where 738 // we'd do something about it if we did. 739 logMsg.data_status.status = event->data; 740 mLogger->Log(LOG_DATA_STATUS_HANDLED, logMsg); 741 break; 742 743 default: 744 // hmm, someone enqueued a message that we don't understand. log and ignore it. 745 logMsg.unknown.what = event->type; 746 mLogger->Log(LOG_HANDLE_UNKNOWN, logMsg); 747 break; 748 } 749 } 750