bool OfflineAudioDestinationHandler::renderIfNotSuspended(AudioBus* sourceBus, AudioBus* destinationBus, size_t numberOfFrames)
{
    // We don't want denormals slowing down any of the audio processing
    // since they can very seriously hurt performance.
    // This will take care of all AudioNodes because they all process within this scope.
    DenormalDisabler denormalDisabler;

    context()->deferredTaskHandler().setAudioThread(currentThread());

    if (!context()->isDestinationInitialized()) {
        destinationBus->zero();
        return false;
    }

    // Take care pre-render tasks at the beginning of each render quantum. Then
    // it will stop the rendering loop if the context needs to be suspended
    // at the beginning of the next render quantum.
    if (context()->handlePreOfflineRenderTasks()) {
        suspendOfflineRendering();
        return true;
    }

    // Prepare the local audio input provider for this render quantum.
    if (sourceBus)
        m_localAudioInputProvider.set(sourceBus);

    ASSERT(numberOfInputs() >= 1);
    if (numberOfInputs() < 1) {
        destinationBus->zero();
        return false;
    }
    // This will cause the node(s) connected to us to process, which in turn will pull on their input(s),
    // all the way backwards through the rendering graph.
    AudioBus* renderedBus = input(0).pull(destinationBus, numberOfFrames);

    if (!renderedBus) {
        destinationBus->zero();
    } else if (renderedBus != destinationBus) {
        // in-place processing was not possible - so copy
        destinationBus->copyFrom(*renderedBus);
    }

    // Process nodes which need a little extra help because they are not connected to anything, but still need to process.
    context()->deferredTaskHandler().processAutomaticPullNodes(numberOfFrames);

    // Let the context take care of any business at the end of each render quantum.
    context()->handlePostOfflineRenderTasks();

    // Advance current sample-frame.
    size_t newSampleFrame = m_currentSampleFrame + numberOfFrames;
    releaseStore(&m_currentSampleFrame, newSampleFrame);

    return false;
}
bool OfflineAudioDestinationHandler::renderIfNotSuspended(AudioBus* sourceBus, AudioBus* destinationBus, size_t numberOfFrames)
{
    // We don't want denormals slowing down any of the audio processing
    // since they can very seriously hurt performance.
    // This will take care of all AudioNodes because they all process within this scope.
    DenormalDisabler denormalDisabler;

    // Need to check if the context actually alive. Otherwise the subsequent
    // steps will fail. If the context is not alive somehow, return immediately
    // and do nothing.
    //
    // TODO(hongchan): because the context can go away while rendering, so this
    // check cannot guarantee the safe execution of the following steps.
    ASSERT(context());
    if (!context())
        return false;

    context()->deferredTaskHandler().setAudioThread(currentThread());

    // If the destination node is not initialized, pass the silence to the final
    // audio destination (one step before the FIFO). This check is for the case
    // where the destination is in the middle of tearing down process.
    if (!isInitialized()) {
        destinationBus->zero();
        return false;
    }

    // Take care pre-render tasks at the beginning of each render quantum. Then
    // it will stop the rendering loop if the context needs to be suspended
    // at the beginning of the next render quantum.
    if (context()->handlePreOfflineRenderTasks()) {
        suspendOfflineRendering();
        return true;
    }

    // Prepare the local audio input provider for this render quantum.
    if (sourceBus)
        m_localAudioInputProvider.set(sourceBus);

    ASSERT(numberOfInputs() >= 1);
    if (numberOfInputs() < 1) {
        destinationBus->zero();
        return false;
    }
    // This will cause the node(s) connected to us to process, which in turn will pull on their input(s),
    // all the way backwards through the rendering graph.
    AudioBus* renderedBus = input(0).pull(destinationBus, numberOfFrames);

    if (!renderedBus) {
        destinationBus->zero();
    } else if (renderedBus != destinationBus) {
        // in-place processing was not possible - so copy
        destinationBus->copyFrom(*renderedBus);
    }

    // Process nodes which need a little extra help because they are not connected to anything, but still need to process.
    context()->deferredTaskHandler().processAutomaticPullNodes(numberOfFrames);

    // Let the context take care of any business at the end of each render quantum.
    context()->handlePostOfflineRenderTasks();

    // Advance current sample-frame.
    size_t newSampleFrame = m_currentSampleFrame + numberOfFrames;
    releaseStore(&m_currentSampleFrame, newSampleFrame);

    return false;
}