Example #1
0
void
SystemClockDriver::GetIntervalForIteration(GraphTime& aFrom, GraphTime& aTo)
{
  TimeStamp now = TimeStamp::Now();
  aFrom = mIterationStart = IterationEnd();
  aTo = mIterationEnd = mGraphImpl->SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + IterationEnd();

  mCurrentTimeStamp = now;

  PR_LOG(gMediaStreamGraphLog, PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)",
         mGraphImpl->MediaTimeToSeconds(aTo),
         (now - mInitialTimeStamp).ToSeconds(),
         mGraphImpl->MediaTimeToSeconds(StateComputedTime())));

  if (mStateComputedTime < aTo) {
    STREAM_LOG(PR_LOG_WARNING, ("Media graph global underrun detected"));
    aTo = mIterationEnd = mStateComputedTime;
  }

  if (aFrom >= aTo) {
    NS_ASSERTION(aFrom == aTo , "Time can't go backwards!");
    // This could happen due to low clock resolution, maybe?
    STREAM_LOG(PR_LOG_DEBUG, ("Time did not advance"));
  }
}
Example #2
0
void
ThreadedDriver::RunThread()
{
  AutoProfilerUnregisterThread autoUnregister;

  bool stillProcessing = true;
  while (stillProcessing) {
    GraphTime prevCurrentTime, nextCurrentTime;
    GetIntervalForIteration(prevCurrentTime, nextCurrentTime);

    mStateComputedTime = mNextStateComputedTime;
    mNextStateComputedTime =
      mGraphImpl->RoundUpToNextAudioBlock(
        nextCurrentTime + mGraphImpl->MillisecondsToMediaTime(AUDIO_TARGET_MS));
    STREAM_LOG(PR_LOG_DEBUG,
               ("interval[%ld; %ld] state[%ld; %ld]",
               (long)mIterationStart, (long)mIterationEnd,
               (long)mStateComputedTime, (long)mNextStateComputedTime));

    stillProcessing = mGraphImpl->OneIteration(prevCurrentTime,
                                               nextCurrentTime,
                                               StateComputedTime(),
                                               mNextStateComputedTime);

    if (mNextDriver && stillProcessing) {
      STREAM_LOG(PR_LOG_DEBUG, ("Switching to AudioCallbackDriver"));
      mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd,
                                 mStateComputedTime, mNextStateComputedTime);
      mGraphImpl->SetCurrentDriver(mNextDriver);
      mNextDriver->Start();
      return;
    }
  }
}
Example #3
0
void
ThreadedDriver::RunThread()
{
    AutoProfilerUnregisterThread autoUnregister;

    bool stillProcessing = true;
    while (stillProcessing) {
        mIterationStart = IterationEnd();
        mIterationEnd += GetIntervalForIteration();

        GraphTime stateComputedTime = StateComputedTime();
        if (stateComputedTime < mIterationEnd) {
            STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected"));
            mIterationEnd = stateComputedTime;
        }

        if (mIterationStart >= mIterationEnd) {
            NS_ASSERTION(mIterationStart == mIterationEnd ,
                         "Time can't go backwards!");
            // This could happen due to low clock resolution, maybe?
            STREAM_LOG(LogLevel::Debug, ("Time did not advance"));
        }

        GraphTime nextStateComputedTime =
            mGraphImpl->RoundUpToNextAudioBlock(
                mIterationEnd + mGraphImpl->MillisecondsToMediaTime(AUDIO_TARGET_MS));
        if (nextStateComputedTime < stateComputedTime) {
            // A previous driver may have been processing further ahead of
            // iterationEnd.
            STREAM_LOG(LogLevel::Warning,
                       ("Prevent state from going backwards. interval[%ld; %ld] state[%ld; %ld]",
                        (long)mIterationStart, (long)mIterationEnd,
                        (long)stateComputedTime, (long)nextStateComputedTime));
            nextStateComputedTime = stateComputedTime;
        }
        STREAM_LOG(LogLevel::Debug,
                   ("interval[%ld; %ld] state[%ld; %ld]",
                    (long)mIterationStart, (long)mIterationEnd,
                    (long)stateComputedTime, (long)nextStateComputedTime));

        stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);

        if (mNextDriver && stillProcessing) {
            STREAM_LOG(LogLevel::Debug, ("Switching to AudioCallbackDriver"));
            mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
            mGraphImpl->SetCurrentDriver(mNextDriver);
            mNextDriver->Start();
            return;
        }
    }
}
Example #4
0
MediaTime
SystemClockDriver::GetIntervalForIteration()
{
    TimeStamp now = TimeStamp::Now();
    MediaTime interval =
        mGraphImpl->SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds());
    mCurrentTimeStamp = now;

    MOZ_LOG(gMediaStreamGraphLog, LogLevel::Verbose,
            ("Updating current time to %f (real %f, StateComputedTime() %f)",
             mGraphImpl->MediaTimeToSeconds(IterationEnd() + interval),
             (now - mInitialTimeStamp).ToSeconds(),
             mGraphImpl->MediaTimeToSeconds(StateComputedTime())));

    return interval;
}
Example #5
0
long
AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames)
{
    bool stillProcessing;

    if (mPauseRequested) {
        PodZero(aBuffer, aFrames * mGraphImpl->AudioChannelCount());
        return aFrames;
    }

#ifdef XP_MACOSX
    if (OSXDeviceSwitchingWorkaround()) {
        PodZero(aBuffer, aFrames * mGraphImpl->AudioChannelCount());
        return aFrames;
    }
#endif

#ifdef DEBUG
    // DebugOnly<> doesn't work here... it forces an initialization that will cause
    // mInCallback to be set back to false before we exit the statement.  Do it by
    // hand instead.
    AutoInCallback aic(this);
#endif

    GraphTime stateComputedTime = StateComputedTime();
    if (stateComputedTime == 0) {
        MonitorAutoLock mon(mGraphImpl->GetMonitor());
        // Because this function is called during cubeb_stream_init (to prefill the
        // audio buffers), it can be that we don't have a message here (because this
        // driver is the first one for this graph), and the graph would exit. Simply
        // return here until we have messages.
        if (!mGraphImpl->MessagesQueued()) {
            PodZero(aBuffer, aFrames * mGraphImpl->AudioChannelCount());
            return aFrames;
        }
        mGraphImpl->SwapMessageQueues();
    }

    uint32_t durationMS = aFrames * 1000 / mSampleRate;

    // For now, simply average the duration with the previous
    // duration so there is some damping against sudden changes.
    if (!mIterationDurationMS) {
        mIterationDurationMS = durationMS;
    } else {
        mIterationDurationMS = (mIterationDurationMS*3) + durationMS;
        mIterationDurationMS /= 4;
    }

    mBuffer.SetBuffer(aBuffer, aFrames);
    // fill part or all with leftover data from last iteration (since we
    // align to Audio blocks)
    mScratchBuffer.Empty(mBuffer);
    // if we totally filled the buffer (and mScratchBuffer isn't empty),
    // we don't need to run an iteration and if we do so we may overflow.
    if (mBuffer.Available()) {

        // State computed time is decided by the audio callback's buffer length. We
        // compute the iteration start and end from there, trying to keep the amount
        // of buffering in the graph constant.
        GraphTime nextStateComputedTime =
            mGraphImpl->RoundUpToNextAudioBlock(stateComputedTime + mBuffer.Available());

        mIterationStart = mIterationEnd;
        // inGraph is the number of audio frames there is between the state time and
        // the current time, i.e. the maximum theoretical length of the interval we
        // could use as [mIterationStart; mIterationEnd].
        GraphTime inGraph = stateComputedTime - mIterationStart;
        // We want the interval [mIterationStart; mIterationEnd] to be before the
        // interval [stateComputedTime; nextStateComputedTime]. We also want
        // the distance between these intervals to be roughly equivalent each time, to
        // ensure there is no clock drift between current time and state time. Since
        // we can't act on the state time because we have to fill the audio buffer, we
        // reclock the current time against the state time, here.
        mIterationEnd = mIterationStart + 0.8 * inGraph;

        STREAM_LOG(LogLevel::Debug, ("interval[%ld; %ld] state[%ld; %ld] (frames: %ld) (durationMS: %u) (duration ticks: %ld)\n",
                                     (long)mIterationStart, (long)mIterationEnd,
                                     (long)stateComputedTime, (long)nextStateComputedTime,
                                     (long)aFrames, (uint32_t)durationMS,
                                     (long)(nextStateComputedTime - stateComputedTime)));

        mCurrentTimeStamp = TimeStamp::Now();

        if (stateComputedTime < mIterationEnd) {
            STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected"));
            mIterationEnd = stateComputedTime;
        }

        stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
    } else {
        NS_WARNING("DataCallback buffer filled entirely from scratch buffer, skipping iteration.");
        stillProcessing = true;
    }

    mBuffer.BufferFilled();

    if (mNextDriver && stillProcessing) {
        {
            // If the audio stream has not been started by the previous driver or
            // the graph itself, keep it alive.
            MonitorAutoLock mon(mGraphImpl->GetMonitor());
            if (!IsStarted()) {
                return aFrames;
            }
        }
        STREAM_LOG(LogLevel::Debug, ("Switching to system driver."));
        mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
        mGraphImpl->SetCurrentDriver(mNextDriver);
        mNextDriver->Start();
        // Returning less than aFrames starts the draining and eventually stops the
        // audio thread. This function will never get called again.
        return aFrames - 1;
    }

    if (!stillProcessing) {
        LIFECYCLE_LOG("Stopping audio thread for MediaStreamGraph %p", this);
        return aFrames - 1;
    }
    return aFrames;
}