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