void MediaSink::stopPlaying() { // First, tell the source that we're no longer interested: if (fSource != NULL) fSource->stopGettingFrames(); // Cancel any pending tasks: envir().taskScheduler().unscheduleDelayedTask(nextTask()); nextTask() = NULL; fSource = NULL; // indicates that we can be played again fAfterFunc = NULL; }
void MultiFramedRTPSink::buildAndSendPacket(Boolean isFirstPacket) { nextTask() = NULL; fIsFirstPacket = isFirstPacket; // Set up the RTP header: unsigned rtpHdr = 0x80000000; // RTP version 2; marker ('M') bit not set (by default; it can be set later) rtpHdr |= (fRTPPayloadType<<16); rtpHdr |= fSeqNo; // sequence number fOutBuf->enqueueWord(rtpHdr); // Note where the RTP timestamp will go. // (We can't fill this in until we start packing payload frames.) fTimestampPosition = fOutBuf->curPacketSize(); fOutBuf->skipBytes(4); // leave a hole for the timestamp fOutBuf->enqueueWord(SSRC()); // Allow for a special, payload-format-specific header following the // RTP header: fSpecialHeaderPosition = fOutBuf->curPacketSize(); fSpecialHeaderSize = specialHeaderSize(); fOutBuf->skipBytes(fSpecialHeaderSize); // Begin packing as many (complete) frames into the packet as we can: fTotalFrameSpecificHeaderSizes = 0; fNoFramesLeft = False; fNumFramesUsedSoFar = 0; packFrame(); }
void BasicUDPSink::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, unsigned durationInMicroseconds) { if (numTruncatedBytes > 0) { envir() << "BasicUDPSink::afterGettingFrame1(): The input frame data was too large for our spcified maximum payload size (" << fMaxPayloadSize << "). " << numTruncatedBytes << " bytes of trailing data was dropped!\n"; } // Send the packet: fGS->output(envir(), fGS->ttl(), fOutputBuffer, frameSize); // Figure out the time at which the next packet should be sent, based // on the duration of the payload that we just read: fNextSendTime.tv_usec += durationInMicroseconds; fNextSendTime.tv_sec += fNextSendTime.tv_usec/1000000; fNextSendTime.tv_usec %= 1000000; struct timeval timeNow; gettimeofday(&timeNow, NULL); int uSecondsToGo; if (fNextSendTime.tv_sec < timeNow.tv_sec) { uSecondsToGo = 0; // prevents integer underflow if too far behind } else { uSecondsToGo = (fNextSendTime.tv_sec - timeNow.tv_sec)*1000000 + (fNextSendTime.tv_usec - timeNow.tv_usec); } // Delay this amount of time: nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, (TaskFunc*)sendNext, this); }
void BasicUDPSink::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, unsigned durationInMicroseconds) { if (numTruncatedBytes > 0) { envir() << "BasicUDPSink::afterGettingFrame1(): The input frame data was too large for our spcified maximum payload size (" << fMaxPayloadSize << "). " << numTruncatedBytes << " bytes of trailing data was dropped!\n"; } // Send the packet: fGS->output(envir(), fOutputBuffer, frameSize); // Figure out the time at which the next packet should be sent, based // on the duration of the payload that we just read: fNextSendTime.tv_usec += durationInMicroseconds; fNextSendTime.tv_sec += fNextSendTime.tv_usec/1000000; fNextSendTime.tv_usec %= 1000000; struct timeval timeNow; gettimeofday(&timeNow, NULL); int secsDiff = fNextSendTime.tv_sec - timeNow.tv_sec; int64_t uSecondsToGo = secsDiff*1000000 + (fNextSendTime.tv_usec - timeNow.tv_usec); if (uSecondsToGo < 0 || secsDiff < 0) { // sanity check: Make sure that the time-to-delay is non-negative: uSecondsToGo = 0; } // Delay this amount of time: nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, (TaskFunc*)sendNext, this); }
void QueueServerMediaSubsession::afterPlayingDummy1() { // Unschedule any pending 'checking' task: envir().taskScheduler().unscheduleDelayedTask(nextTask()); // Signal the event loop that we're done: setDoneFlag(); }
void ByteStreamFileSource::doStopGettingFrames() { envir().taskScheduler().unscheduleDelayedTask(nextTask()); #ifndef READ_FROM_FILES_SYNCHRONOUSLY envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid)); fHaveStartedReading = False; #endif }
// Note: We should change the following to use asynchronous file reading, ##### // as we now do with ByteStreamFileSource. ##### void AMRAudioFileSource::doGetNextFrame() { if (feof(fFid) || ferror(fFid)) { handleClosure(this); return; } // Begin by reading the 1-byte frame header (and checking it for validity) while (1) { if (fread(&fLastFrameHeader, 1, 1, fFid) < 1) { handleClosure(this); return; } if ((fLastFrameHeader&0x83) != 0) { #ifdef DEBUG fprintf(stderr, "Invalid frame header 0x%02x (padding bits (0x83) are not zero)\n", fLastFrameHeader); #endif } else { unsigned char ft = (fLastFrameHeader&0x78)>>3; fFrameSize = fIsWideband ? frameSizeWideband[ft] : frameSize[ft]; if (fFrameSize == FT_INVALID) { #ifdef DEBUG fprintf(stderr, "Invalid FT field %d (from frame header 0x%02x)\n", ft, fLastFrameHeader); #endif } else { // The frame header is OK #ifdef DEBUG fprintf(stderr, "Valid frame header 0x%02x -> ft %d -> frame size %d\n", fLastFrameHeader, ft, fFrameSize); #endif break; } } } // Next, read the frame-block into the buffer provided: fFrameSize *= fNumChannels; // because multiple channels make up a frame-block if (fFrameSize > fMaxSize) { fNumTruncatedBytes = fFrameSize - fMaxSize; fFrameSize = fMaxSize; } fFrameSize = fread(fTo, 1, fFrameSize, fFid); // Set the 'presentation time': if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { // This is the first frame, so use the current time: gettimeofday(&fPresentationTime, NULL); } else { // Increment by the play time of the previous frame (20 ms) unsigned uSeconds = fPresentationTime.tv_usec + 20000; fPresentationTime.tv_sec += uSeconds/1000000; fPresentationTime.tv_usec = uSeconds%1000000; } fDurationInMicroseconds = 20000; // each frame is 20 ms // Switch to another task, and inform the reader that he has data: nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this); }
void BasicUDPSink::continuePlaying1() { nextTask() = NULL; if (fSource != NULL) { fSource->getNextFrame(fOutputBuffer, fMaxPayloadSize, afterGettingFrame, this, onSourceClosure, this); } }
void MediaSink::onSourceClosure() { // Cancel any pending tasks: envir().taskScheduler().unscheduleDelayedTask(nextTask()); fSource = NULL; // indicates that we can be played again if (fAfterFunc != NULL) { (*fAfterFunc)(fAfterClientData); } }
void ByteStreamFileSource::doReadFromFile() { // Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less) if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) { fMaxSize = (unsigned)fNumBytesToStream; } if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) { fMaxSize = fPreferredFrameSize; } #ifdef READ_FROM_FILES_SYNCHRONOUSLY fFrameSize = fread(fTo, 1, fMaxSize, fFid); #else if (fFidIsSeekable) { fFrameSize = fread(fTo, 1, fMaxSize, fFid); } else { // For non-seekable files (e.g., pipes), call "read()" rather than "fread()", to ensure that the read doesn't block: fFrameSize = read(fileno(fFid), fTo, fMaxSize); } #endif if (fFrameSize == 0) { handleClosure(); return; } fNumBytesToStream -= fFrameSize; // Set the 'presentation time': if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) { if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { // This is the first frame, so use the current time: gettimeofday(&fPresentationTime, NULL); } else { // Increment by the play time of the previous data: unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime; fPresentationTime.tv_sec += uSeconds/1000000; fPresentationTime.tv_usec = uSeconds%1000000; } // Remember the play time of this data: fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize; fDurationInMicroseconds = fLastPlayTime; } else { // We don't know a specific play time duration for this data, // so just record the current time as being the 'presentation time': gettimeofday(&fPresentationTime, NULL); } // Inform the reader that he has data: #ifdef READ_FROM_FILES_SYNCHRONOUSLY // To avoid possible infinite recursion, we need to return to the event loop to do this: nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this); #else // Because the file read was done from the event loop, we can call the // 'after getting' function directly, without risk of infinite recursion: FramedSource::afterGetting(this); #endif }
void MultiFramedRTPSource::doStopGettingFrames() { if (fPacketReadInProgress != NULL) { fReorderingBuffer->freePacket(fPacketReadInProgress); fPacketReadInProgress = NULL; } envir().taskScheduler().unscheduleDelayedTask(nextTask()); fRTPInterface.stopNetworkReading(); fReorderingBuffer->reset(); reset(); }
void MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1() { nextTask() = NULL; char const* dasl; if (fAuxSDPLine != NULL) { // Signal the event loop that we're done: setDoneFlag(); } else if (fDummyRTPSink != NULL && (dasl = fDummyRTPSink->auxSDPLine()) != NULL) { fAuxSDPLine= strDup(dasl); fDummyRTPSink = NULL; // Signal the event loop that we're done: setDoneFlag(); } else if (!fDoneFlag) { // try again after a brief delay: int uSecsToDelay = 100000; // 100 ms nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay, (TaskFunc*)checkForAuxSDPLine, this); } }
//从文件中读取fMaxSize个字节到fTo void ByteStreamFileSource::doReadFromFile() { // Try to read as many bytes as will fit in the buffer provided // (or "fPreferredFrameSize" if less) if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) { fMaxSize = fPreferredFrameSize; } DEBUG_LOG(INF, "Read file: start = %ld, size= %u; Write to %p", ftell(fFid), fMaxSize, fTo); fFrameSize = fread(fTo, 1, fMaxSize, fFid);//fread(buffer,size,count,fp); if (fFrameSize == 0) { handleClosure(this); return; } // 设置图像时间,Set the 'presentation time': if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) { if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { // fPresentationTime为零,表示这是第一帧,This is the first frame, so use the current time: gettimeofday(&fPresentationTime, NULL); } else { // Increment by the play time of the previous data: // 根据上次的fPresentationTime和上次的持续时间计算新的fPresentationTime unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime; fPresentationTime.tv_sec += uSeconds/1000000; fPresentationTime.tv_usec = uSeconds%1000000; } // Remember the play time of this data: fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize; fDurationInMicroseconds = fLastPlayTime; } else { // We don't know a specific play time duration for this data, // so just record the current time as being the 'presentation time': gettimeofday(&fPresentationTime, NULL); } // Inform the reader that he has data: #ifdef READ_FROM_FILES_SYNCHRONOUSLY // To avoid possible infinite recursion, we need to return to the event loop to do this: nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this); #else // Because the file read was done from the event loop, we can call the // 'after getting' function directly, without risk of infinite recursion: FramedSource::afterGetting(this); #endif }
void WISH264VideoServerMediaSubsession::checkForAuxSDPLine1() { if (fDummyRTPSink->auxSDPLine() != NULL) { // Signal the event loop that we're done: setDoneFlag(); } else { // try again after a brief delay: int uSecsToDelay = 100000; // 100 ms nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay, (TaskFunc*)checkForAuxSDPLine, this); } }
void RTCPInstance::schedule(double nextTime) { fNextReportTime = nextTime; double secondsToDelay = nextTime - dTimeNow(); #ifdef DEBUG fprintf(stderr, "schedule(%f->%f)\n", secondsToDelay, nextTime); #endif int usToGo = (int)(secondsToDelay * 1000000); nextTask() = envir().taskScheduler().scheduleDelayedTask(usToGo, (TaskFunc*)RTCPInstance::onExpire, this); }
void chkForAuxSDPLine1 () { fprintf(stderr, "[%d] %s .... calling\n", gettid(), __func__); if (mp_dummy_rtpsink->auxSDPLine()) m_done = 0xff; else { int delay = 100*1000; // 100ms nextTask() = envir().taskScheduler().scheduleDelayedTask(delay, chkForAuxSDPLine, this); } }
void DefaultSource::doGetNextFrame() { auto const CODE = _reader->read(fTo, fMaxSize, &fFrameSize, &fPresentationTime); if (isFailure(CODE)) { handleClosure(); return; } // Inform the reader that he has data: // To avoid possible infinite recursion, we need to return to the event loop to do this: nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this); }
void MultiFramedRTPSink::sendPacketIfNecessary() { if (fNumFramesUsedSoFar > 0) { // Send the packet: #ifdef TEST_LOSS if ((our_random()%10) != 0) // simulate 10% packet loss ##### #endif if (!fRTPInterface.sendPacket(fOutBuf->packet(), fOutBuf->curPacketSize())) { // if failure handler has been specified, call it if (fOnSendErrorFunc != NULL) (*fOnSendErrorFunc)(fOnSendErrorData); } ++fPacketCount; fTotalOctetCount += fOutBuf->curPacketSize(); fOctetCount += fOutBuf->curPacketSize() - rtpHeaderSize - fSpecialHeaderSize - fTotalFrameSpecificHeaderSizes; ++fSeqNo; // for next time } if (fOutBuf->haveOverflowData() && fOutBuf->totalBytesAvailable() > fOutBuf->totalBufferSize()/2) { // Efficiency hack: Reset the packet start pointer to just in front of // the overflow data (allowing for the RTP header and special headers), // so that we probably don't have to "memmove()" the overflow data // into place when building the next packet: unsigned newPacketStart = fOutBuf->curPacketSize() - (rtpHeaderSize + fSpecialHeaderSize + frameSpecificHeaderSize()); fOutBuf->adjustPacketStart(newPacketStart); } else { // Normal case: Reset the packet start pointer back to the start: fOutBuf->resetPacketStart(); } fOutBuf->resetOffset(); fNumFramesUsedSoFar = 0; if (fNoFramesLeft) { // We're done: onSourceClosure(); } else { // We have more frames left to send. Figure out when the next frame // is due to start playing, then make sure that we wait this long before // sending the next packet. struct timeval timeNow; gettimeofday(&timeNow, NULL); int secsDiff = fNextSendTime.tv_sec - timeNow.tv_sec; int64_t uSecondsToGo = secsDiff*1000000 + (fNextSendTime.tv_usec - timeNow.tv_usec); if (uSecondsToGo < 0 || secsDiff < 0) { // sanity check: Make sure that the time-to-delay is non-negative: uSecondsToGo = 0; } // Delay this amount of time: nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, (TaskFunc*)sendNext, this); } }
void H264LiveServerMediaSession::checkForAuxSDPLine1() { char const* dasl; if (fAuxSDPLine != NULL) { setDoneFlag(); } else if (fDummySink != NULL && (dasl = fDummySink->auxSDPLine()) != NULL) { fAuxSDPLine = strDup(dasl); fDummySink = NULL; setDoneFlag(); } else { int uSecsDelay = 100000; nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsDelay, (TaskFunc*) checkForAuxSDPLine, this); } }
void StreamDeviceSource::deliverFrame() { // This function is called when new frame data is available from the device. // We deliver this data by copying it to the 'downstream' object, using the following parameters (class members): // 'in' parameters (these should *not* be modified by this function): // fTo: The frame data is copied to this address. // (Note that the variable "fTo" is *not* modified. Instead, // the frame data is copied to the address pointed to by "fTo".) // fMaxSize: This is the maximum number of bytes that can be copied // (If the actual frame is larger than this, then it should // be truncated, and "fNumTruncatedBytes" set accordingly.) // 'out' parameters (these are modified by this function): // fFrameSize: Should be set to the delivered frame size (<= fMaxSize). // fNumTruncatedBytes: Should be set iff the delivered frame would have been // bigger than "fMaxSize", in which case it's set to the number of bytes // that have been omitted. // fPresentationTime: Should be set to the frame's presentation time // (seconds, microseconds). This time must be aligned with 'wall-clock time' - i.e., the time that you would get // by calling "gettimeofday()". // fDurationInMicroseconds: Should be set to the frame's duration, if known. // If, however, the device is a 'live source' (e.g., encoded from a camera or microphone), then we probably don't need // to set this variable, because - in this case - data will never arrive 'early'. // Note the code below. if (isCurrentlyAwaitingData()) return; // we're not ready for the data yet // allocate temporary buffer static void *buffer = NULL; if (NULL == buffer) { buffer = malloc(8192); } // by specifying length = 8192 we telling to discardBytesFromGlobalCircularBuffer that it may copy maximum 8192 bytes int32_t length = 8192; discardBytesFromGlobalCircularBuffer(&buffer, &length); u_int8_t* newFrameDataStart = (u_int8_t*)buffer; unsigned newFrameSize = length; // Deliver the data here: if (newFrameSize > fMaxSize) { fFrameSize = fMaxSize; fNumTruncatedBytes = newFrameSize - fMaxSize; } else { fFrameSize = newFrameSize; } gettimeofday(&fPresentationTime, NULL); // If you have a more accurate time - e.g., from an encoder - then use that instead. // If the device is *not* a 'live source' (e.g., it comes instead from a file or buffer), then set "fDurationInMicroseconds" here. memmove(fTo, newFrameDataStart, fFrameSize); // After delivering the data, inform the reader that it is now available: nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this); }
/** resets the current state, creates a new task and count the last task as * wrong, if it wasn't solved (in _NEXT_TASK state) yet * mainly used after changing the task parameters */ void ExerciseCompare::forceNewTask() { #ifdef DEBUG qDebug() << QStringLiteral("forceNewTask ExerciseCompare()"); #endif if (m_currentState == _CHECK_TASK) { // emit the signal for skipped signalExerciseSkipped(); } m_currentState = _CHECK_TASK; // generate next task (void) nextTask(); }
void ExerciseCompare::slotSkipButtonClicked() { #ifdef DEBUG qDebug() << "ExerciseCompare::slotSkipButtonClicked()"; #endif if (m_currentState == _CHECK_TASK) { forceNewTask(); } else { m_currentState = _CHECK_TASK; m_skipButton->setText(i18n("&Skip")); m_resultWidget->setResult(m_firstRatio, -1); nextTask(); } return; }
void RTCPInstance::schedule(double nextTime) { fNextReportTime = nextTime; double secondsToDelay = nextTime - dTimeNow(); if (secondsToDelay < 0) secondsToDelay = 0; #ifdef DEBUG #ifdef __LINUX__ fprintf(stderr, "schedule(%f->%f)\n", secondsToDelay, nextTime); #else fprintf(stderr, "schedule(%ld->%ld) us\n", (int64_t)(secondsToDelay*1000000), (int64_t)(nextTime*1000000)); #endif #endif int64_t usToGo = (int64_t)(secondsToDelay * 1000000); nextTask() = envir().taskScheduler().scheduleDelayedTask(usToGo, (TaskFunc*)RTCPInstance::onExpire, this); }
void chk_sdp_done1 () { if (mp_sdp_line) { m_done = 1; } else if (mp_dump_sink && mp_dump_sink->auxSDPLine()) { mp_sdp_line = strdup(mp_dump_sink->auxSDPLine()); mp_dump_sink = 0; m_done = 1; } else { // try again nextTask() = envir().taskScheduler().scheduleDelayedTask(100000, // 100ms chk_sdp_done, this); } }
/** resets the current state, creates a new task and count the last task as * wrong, if it wasn't solved (in _NEXT_TASK state) yet * mainly used after changing the task parameters */ void TaskView::forceNewTask() { #ifdef DEBUG kdDebug() << "forceNewTask TaskView()" << endl; #endif if (m_currentState == _CHECK_TASK) { // emit the signal for wrong signalTaskSolvedWrong(); } m_currentState = _CHECK_TASK; m_checkButton->setText(i18n("&Check Task")); // generate next task (void) nextTask(); }
void TaskView::slotCheckButtonClicked() { if (m_currentState == _CHECK_TASK) { // if nothing has been entered by the user, we don't check the result yet if (numer_edit->text().isEmpty() == true && deno_edit->text().isEmpty() == true) return; m_currentState = _NEXT_TASK; m_checkButton->setText(i18n("N&ext Task")); (void) showResult(); } else { m_currentState = _CHECK_TASK; m_checkButton->setText(i18n("&Check Task")); (void) nextTask(); } }
void H264VideoFileServerMediaSubsession::checkForAuxSDPLine1() { // If encode stream is mjpeg, the done flag is also needed to be set. // If not set for mjpeg, rtsp_server will not come out of DESBRIBE command processing from client // Modified by Zhaoyang //if (fDummyRTPSink->auxSDPLine() != NULL) { #if defined( USE_V3_3_CODE ) if (fEncType == IAV_ENCODE_MJPEG || fDummyRTPSink->auxSDPLine() != NULL) { #else if (fDummyRTPSink->auxSDPLine() != NULL) { #endif // Signal the event loop that we're done: setDoneFlag(); } else { // try again after a brief delay: int uSecsToDelay = 100000; // 100 ms nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay, (TaskFunc*)checkForAuxSDPLine, this); } } char const* H264VideoFileServerMediaSubsession ::getAuxSDPLine(RTPSink* rtpSink, FramedSource* inputSource) { // Note: For MPEG-4 video files, the 'config' information isn't known // until we start reading the file. This means that "rtpSink"s // "auxSDPLine()" will be NULL initially, and we need to start reading // data from our file until this changes. fDummyRTPSink = rtpSink; // Start reading the file: fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this); // Check whether the sink's 'auxSDPLine()' is ready: checkForAuxSDPLine(this); envir().taskScheduler().doEventLoop(&fDoneFlag); char const* auxSDPLine = fDummyRTPSink->auxSDPLine(); return auxSDPLine; }
bool RenderThread::threadLoop() { setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); initThreadLocals(); int timeoutMillis = -1; for (;;) { int result = mLooper->pollOnce(timeoutMillis); LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!"); nsecs_t nextWakeup; // Process our queue, if we have anything while (RenderTask* task = nextTask(&nextWakeup)) { task->run(); // task may have deleted itself, do not reference it again } if (nextWakeup == LLONG_MAX) { timeoutMillis = -1; } else { nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); if (timeoutMillis < 0) { timeoutMillis = 0; } } if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { drainDisplayEventQueue(); mFrameCallbacks.insert( mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); mPendingRegistrationFrameCallbacks.clear(); requestVsync(); } if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) { // TODO: Clean this up. This is working around an issue where a combination // of bad timing and slow drawing can result in dropping a stale vsync // on the floor (correct!) but fails to schedule to listen for the // next vsync (oops), so none of the callbacks are run. requestVsync(); } } return false; }
// Note: We should change the following to use asynchronous file reading, ##### // as we now do with ByteStreamFileSource. ##### void G711AudioStreamSource::doGetNextFrame() { // Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less) if (fLimitNumBytesToStream && fNumBytesToStream < fMaxSize) { fMaxSize = fNumBytesToStream; } if (fPreferredFrameSize < fMaxSize) { fMaxSize = fPreferredFrameSize; } unsigned bytesPerSample = (fNumChannels*fBitsPerSample)/8; if (bytesPerSample == 0) bytesPerSample = 1; // because we can't read less than a byte at a time //unsigned bytesToRead = fMaxSize - fMaxSize%bytesPerSample; //fFrameSize : 1000 audioGetOneFrame(fTo, &fFrameSize); // Set the 'presentation time' and 'duration' of this frame: if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { // This is the first frame, so use the current time: gettimeofday(&fPresentationTime, NULL); } else { // Increment by the play time of the previous data: unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime; fPresentationTime.tv_sec += uSeconds/1000000; fPresentationTime.tv_usec = uSeconds%1000000; } // Remember the play time of this data: fDurationInMicroseconds = fLastPlayTime = (unsigned)((fPlayTimePerSample*fFrameSize)/bytesPerSample); // Switch to another task, and inform the reader that he has data: #if defined(__WIN32__) || defined(_WIN32) // HACK: One of our applications that uses this source uses an // implementation of scheduleDelayedTask() that performs very badly // (chewing up lots of CPU time, apparently polling) on Windows. // Until this is fixed, we just call our "afterGetting()" function // directly. This avoids infinite recursion, as long as our sink // is discontinuous, which is the case for the RTP sink that // this application uses. ##### afterGetting(this); #else nextTask() = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)FramedSource::afterGetting, this); #endif }
void WindowsAudioInputDevice_common::audioReadyPoller1() { if (readHead != NULL) { onceAudioIsReady(); } else { unsigned const maxPollingDelay = (100 + fGranularityInMS)*1000; if (fTotalPollingDelay > maxPollingDelay) { // We've waited too long for the audio device - assume it's down: handleClosure(this); return; } // Try again after a short delay: unsigned const uSecondsToDelay = fGranularityInMS*1000; fTotalPollingDelay += uSecondsToDelay; nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToDelay, (TaskFunc*)audioReadyPoller, this); } }