void StepMotionBlurFilter::LateNoticeReceived( const media_source& source, bigtime_t howLate, bigtime_t tpWhen) { PRINT(("StepMotionBlurFilter::LateNoticeReceived()\n" "\thowLate == %Ld\n" "\twhen == %Ld\n", howLate, tpWhen)); if (source != m_output.source) { PRINT(("\tBad source.\n")); return; } if (m_input.source == media_source::null) { PRINT(("\t!!! No input to blame.\n")); return; } // +++++ check run mode? // pass the buck, since this node doesn't schedule buffer // production NotifyLateProducer(m_input.source, howLate, tpWhen); }
void EqualizerNode::LateNoticeReceived(const media_source &src, bigtime_t late, bigtime_t when) { if (src != fOutputMedia.source || fInputMedia.source == media_source::null) return; NotifyLateProducer(fInputMedia.source, late, when); }
// how should we handle late buffers? drop them? // notify the producer? status_t ESDSinkNode::HandleBuffer( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent) { CALLED(); BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer); if (buffer == 0) { fprintf(stderr,"<- B_BAD_VALUE\n"); return B_BAD_VALUE; } if(fInput.destination.id != buffer->Header()->destination) { fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); return B_MEDIA_BAD_DESTINATION; } media_header* hdr = buffer->Header(); bigtime_t now = TimeSource()->Now(); bigtime_t perf_time = hdr->start_time; // the how_early calculate here doesn't include scheduling latency because // we've already been scheduled to handle the buffer bigtime_t how_early = perf_time - EventLatency() - now; // if the buffer is late, we ignore it and report the fact to the producer // who sent it to us if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode... (RunMode() != B_RECORDING) && // ...or in recording mode (how_early < 0LL)) { //mLateBuffers++; NotifyLateProducer(fInput.source, -how_early, perf_time); fprintf(stderr," <- LATE BUFFER : %lli\n", how_early); buffer->Recycle(); } else { if (fDevice->CanSend()) fDevice->Write(buffer->Data(), buffer->SizeUsed()); } return B_OK; }
void LoggingConsumer::HandleEvent(const media_timed_event *event, bigtime_t /* lateness */, bool /* realTimeEvent */) { log_message logMsg; logMsg.now = TimeSource()->Now(); mLogger->Log(LOG_HANDLE_EVENT, logMsg); switch (event->type) { case BTimedEventQueue::B_HANDLE_BUFFER: { BBuffer* buffer = const_cast<BBuffer*>((BBuffer*) event->pointer); if (buffer) { media_header* hdr = buffer->Header(); if (hdr->destination == mInput.destination.id) { bigtime_t now = TimeSource()->Now(); bigtime_t perf_time = hdr->start_time; // the how_early calculated here doesn't include scheduling latency because // we've already been scheduled to handle the buffer bigtime_t how_early = perf_time - mLatency - now; // logMsg.now is already set logMsg.buffer_data.start_time = perf_time; logMsg.buffer_data.offset = how_early; mLogger->Log(LOG_BUFFER_HANDLED, logMsg); // if the buffer is late, we ignore it and report the fact to the producer // who sent it to us if (how_early < 0) { mLateBuffers++; NotifyLateProducer(mInput.source, -how_early, perf_time); } else { // burn some percentage of our stated latency in CPU time (controlled by // a BParameter). this simulates a user-configurable amount of CPU cost // associated with the consumer. bigtime_t spin_start = ::system_time(); bigtime_t spin_now = spin_start; bigtime_t usecToSpin = bigtime_t(mSpinPercentage / 100.0 * mLatency); while (spin_now - spin_start < usecToSpin) { for (long k = 0; k < 1000000; k++) { /* intentionally blank */ } spin_now = ::system_time(); } } // we're done "processing the buffer;" now we recycle it and return to the loop buffer->Recycle(); } else { //fprintf(stderr, "* Woah! Got a buffer for a different destination!\n"); } } } break; // !!! change to B_PARAMETER as soon as it's available // +++++ e.moon [16jun99] // !!! this can't be right: the parameter value is accessed by the pointer // originally passed to SetParameterValue(). there's no guarantee that // value's still valid, is there? case BTimedEventQueue::B_USER_EVENT: { size_t dataSize = size_t(event->data); int32 param = int32(event->bigdata); logMsg.param.id = param; // handle the message if there's sufficient data provided. we only check against // sizeof(float) because all of our parameters happen to be 4 bytes. if various // parameters took different amounts of data, we'd check the size on a per-parameter // basis. if (dataSize >= sizeof(float)) switch (param) { case LATENCY_PARAM: { float value = *((float*) event->pointer); mLatency = bigtime_t(value* 1000); mLastLatencyChange = logMsg.now; // my latency just changed, so reconfigure the BMediaEventLooper // to give me my events at the proper time SetEventLatency(mLatency); // tell the producer that my latency changed, and broadcast a message // about the parameter change to any applications that may be looking // for it through the BMediaRoster::StartWatching() mechanism. // // if we had more than one input, we'd need to tell *all* producers about // the change in our latency. SendLatencyChange(mInput.source, mInput.destination, EventLatency() + SchedulingLatency()); BroadcastNewParameterValue(logMsg.now, param, &value, sizeof(value)); // log the new latency value, for recordkeeping logMsg.param.value = value; mLogger->Log(LOG_SET_PARAM_HANDLED, logMsg); } break; case CPU_SPIN_PARAM: { float value = *((float*) event->pointer); mSpinPercentage = value; mLastSpinChange = logMsg.now; BroadcastNewParameterValue(logMsg.now, param, &value, sizeof(value)); logMsg.param.value = value; mLogger->Log(LOG_SET_PARAM_HANDLED, logMsg); } break; case PRIORITY_PARAM: { mPriority = *((int32*) event->pointer); // DO NOT use ::set_thead_priority() to directly alter the node's control // thread priority. BMediaEventLooper tracks the priority itself and recalculates // the node's scheduling latency whenever SetPriority() is called. This is VERY // important for correct functioning of a node chain. You should *only* alter a // BMediaEventLooper's priority by calling its SetPriority() method. SetPriority(mPriority); mLastPrioChange = logMsg.now; BroadcastNewParameterValue(logMsg.now, param, &mPriority, sizeof(mPriority)); logMsg.param.value = (float) mPriority; mLogger->Log(LOG_SET_PARAM_HANDLED, logMsg); } break; // log the fact that we "handled" a "set parameter" event for a // nonexistent parameter default: mLogger->Log(LOG_INVALID_PARAM_HANDLED, logMsg); break; } } break; case BTimedEventQueue::B_START: // okay, let's go! mLogger->Log(LOG_START_HANDLED, logMsg); break; case BTimedEventQueue::B_STOP: mLogger->Log(LOG_STOP_HANDLED, logMsg); // stopping implies not handling any more buffers. So, we flush all pending // buffers out of the event queue before returning to the event loop. EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); break; case BTimedEventQueue::B_SEEK: // seeking the log doesn't make any sense, so we just log that we handled the seek // and return without doing anything else mLogger->Log(LOG_SEEK_HANDLED, logMsg); break; case BTimedEventQueue::B_WARP: // similarly, time warps aren't meaningful to the logger, so just record it and return mLogger->Log(LOG_WARP_HANDLED, logMsg); break; case BTimedEventQueue::B_DATA_STATUS: // we really don't care about the producer's data status, but this is where // we'd do something about it if we did. logMsg.data_status.status = event->data; mLogger->Log(LOG_DATA_STATUS_HANDLED, logMsg); break; default: // hmm, someone enqueued a message that we don't understand. log and ignore it. logMsg.unknown.what = event->type; mLogger->Log(LOG_HANDLE_UNKNOWN, logMsg); break; } }