Пример #1
0
bool DeferredTaskHandler::tryLock() {
  // Try to catch cases of using try lock on main thread
  // - it should use regular lock.
  DCHECK(isAudioThread());
  if (!isAudioThread()) {
    // In release build treat tryLock() as lock() (since above
    // DCHECK(isAudioThread) never fires) - this is the best we can do.
    lock();
    return true;
  }
  return m_contextGraphMutex.tryLock();
}
void AudioContext::handlePostRenderTasks()
{
    ASSERT(isAudioThread());
 
    // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
    // from the render graph (in which case they'll render silence).
    bool mustReleaseLock;
    if (tryLock(mustReleaseLock)) {
        // Take care of finishing any derefs where the tryLock() failed previously.
        handleDeferredFinishDerefs();

        // Dynamically clean up nodes which are no longer needed.
        derefFinishedSourceNodes();

        // Finally actually delete.
        deleteMarkedNodes();

        // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
        handleDirtyAudioNodeInputs();
        handleDirtyAudioNodeOutputs();
        
        if (mustReleaseLock)
            unlock();
    }
}
Пример #3
0
void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
{
    ASSERT(isAudioThread());

    for (auto& node : m_renderingAutomaticPullNodes)
        node->processIfNecessary(framesToProcess);
}
Пример #4
0
void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
{
    ASSERT(isAudioThread());

    for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i)
        m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess);
}
Пример #5
0
size_t AudioContext::currentSampleFrame() const
{
    if (isAudioThread())
        return m_destinationNode ? m_destinationNode->audioDestinationHandler().currentSampleFrame() : 0;

    return m_cachedSampleFrame;
}
Пример #6
0
double AudioContext::currentTime() const
{
    if (isAudioThread())
        return m_destinationNode ? m_destinationNode->audioDestinationHandler().currentTime() : 0;

    return m_cachedSampleFrame / static_cast<double>(sampleRate());
}
Пример #7
0
void AudioContext::handlePostRenderTasks()
{
    ASSERT(isAudioThread());

    // Must use a tryLock() here too. Don't worry, the lock will very rarely be contended and this method is called frequently.
    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
    // from the render graph (in which case they'll render silence).
    bool mustReleaseLock;
    if (tryLock(mustReleaseLock)) {
        // Take care of finishing any derefs where the tryLock() failed previously.
        handleDeferredFinishDerefs();

        // Dynamically clean up nodes which are no longer needed.
        derefFinishedSourceNodes();

        // Don't delete in the real-time thread. Let the main thread do it.
        // Ref-counted objects held by certain AudioNodes may not be thread-safe.
        scheduleNodeDeletion();

        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
        handleDirtyAudioSummingJunctions();
        handleDirtyAudioNodeOutputs();

        updateAutomaticPullNodes();

        if (mustReleaseLock)
            unlock();
    }
}
Пример #8
0
void AudioContext::handleDeferredFinishDerefs()
{
    ASSERT(isAudioThread() && isGraphOwner());
    for (auto& node : m_deferredFinishDerefList)
        node->finishDeref(AudioNode::RefTypeConnection);
    
    m_deferredFinishDerefList.clear();
}
Пример #9
0
void DeferredTaskHandler::breakConnections() {
  DCHECK(isAudioThread());
  ASSERT(isGraphOwner());

  for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i)
    m_deferredBreakConnectionList[i]->breakConnectionWithLock();
  m_deferredBreakConnectionList.clear();
}
Пример #10
0
void AudioContext::derefFinishedSourceNodes()
{
    ASSERT(isGraphOwner());
    ASSERT(isAudioThread() || isAudioThreadFinished());
    for (auto& node : m_finishedNodes)
        derefNode(node);

    m_finishedNodes.clear();
}
Пример #11
0
void AudioContext::derefFinishedSourceNodes()
{
    ASSERT(isGraphOwner());
    ASSERT(isAudioThread() || isAudioThreadFinished());
    for (unsigned i = 0; i < m_finishedNodes.size(); i++)
        derefNode(m_finishedNodes[i]);

    m_finishedNodes.clear();
}
Пример #12
0
void DeferredTaskHandler::offlineLock() {
  // CHECK is here to make sure to explicitly crash if this is called from
  // other than the offline render thread, which is considered as the audio
  // thread in OfflineAudioContext.
  CHECK(isAudioThread()) << "DeferredTaskHandler::offlineLock() must be called "
                            "within the offline audio thread.";

  m_contextGraphMutex.lock();
}
void DeferredTaskHandler::offlineLock()
{
    // RELEASE_ASSERT is here to make sure to explicitly crash if this is called
    // from other than the offline render thread, which is considered as the
    // audio thread in OfflineAudioContext.
    RELEASE_ASSERT_WITH_MESSAGE(isAudioThread(),
                                "DeferredTaskHandler::offlineLock() must be called within the offline audio thread.");

    m_contextGraphMutex.lock();
}
void DeferredTaskHandler::requestToDeleteHandlersOnMainThread()
{
    ASSERT(isGraphOwner());
    ASSERT(isAudioThread());
    if (m_renderingOrphanHandlers.isEmpty())
        return;
    m_deletableOrphanHandlers.appendVector(m_renderingOrphanHandlers);
    m_renderingOrphanHandlers.clear();
    Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&DeferredTaskHandler::deleteHandlersOnMainThread, PassRefPtr<DeferredTaskHandler>(this)));
}
Пример #15
0
void AudioContext::handleDeferredFinishDerefs()
{
    ASSERT(isAudioThread() && isGraphOwner());
    for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
        AudioNode* node = m_deferredFinishDerefList[i];
        node->finishDeref(AudioNode::RefTypeConnection);
    }
    
    m_deferredFinishDerefList.clear();
}
Пример #16
0
void AudioContext::resolvePromisesForSuspend()
{
    // This runs inside the AudioContext's lock when handling pre-render tasks.
    ASSERT(isAudioThread());
    ASSERT(isGraphOwner());

    // Resolve any pending promises created by suspend()
    if (m_suspendResolvers.size() > 0)
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&AudioContext::resolvePromisesForSuspendOnMainThread, this));
}
bool OfflineAudioContext::shouldSuspend()
{
    ASSERT(isAudioThread());

    // Note that the GraphLock is required before this check. Since this needs
    // to run on the audio thread, OfflineGraphAutoLocker must be used.
    if (m_scheduledSuspends.contains(currentSampleFrame()))
        return true;

    return false;
}
void OfflineAudioContext::handlePostOfflineRenderTasks()
{
    ASSERT(isAudioThread());

    // OfflineGraphAutoLocker here locks the audio graph for the same reason
    // above in |handlePreOfflineRenderTasks|.
    OfflineGraphAutoLocker locker(this);

    deferredTaskHandler().breakConnections();
    releaseFinishedSourceNodes();
    deferredTaskHandler().handleDeferredTasks();
    deferredTaskHandler().requestToDeleteHandlersOnMainThread();
}
Пример #19
0
void AudioContext::resolvePromisesForResume()
{
    // This runs inside the AudioContext's lock when handling pre-render tasks.
    ASSERT(isAudioThread());
    ASSERT(isGraphOwner());

    // Resolve any pending promises created by resume(). Only do this if we haven't already started
    // resolving these promises. This gets called very often and it takes some time to resolve the
    // promises in the main thread.
    if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) {
        m_isResolvingResumePromises = true;
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&AudioContext::resolvePromisesForResumeOnMainThread, this));
    }
}
bool OfflineAudioContext::handlePreOfflineRenderTasks()
{
    ASSERT(isAudioThread());

    // OfflineGraphAutoLocker here locks the audio graph for this scope. Note
    // that this locker does not use tryLock() inside because the timing of
    // suspension MUST NOT be delayed.
    OfflineGraphAutoLocker locker(this);

    deferredTaskHandler().handleDeferredTasks();
    handleStoppableSourceNodes();

    return shouldSuspend();
}
void AbstractAudioContext::releaseFinishedSourceNodes()
{
    ASSERT(isGraphOwner());
    ASSERT(isAudioThread());
    for (AudioHandler* handler : m_finishedSourceHandlers) {
        for (unsigned i = 0; i < m_activeSourceNodes.size(); ++i) {
            if (handler == &m_activeSourceNodes[i]->handler()) {
                handler->breakConnection();
                m_activeSourceNodes.remove(i);
                break;
            }
        }
    }

    m_finishedSourceHandlers.clear();
}
Пример #22
0
void AudioContext::handlePreRenderTasks()
{
    ASSERT(isAudioThread());
 
    // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
    // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
    bool mustReleaseLock;
    if (tryLock(mustReleaseLock)) {
        // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
        handleDirtyAudioNodeInputs();
        handleDirtyAudioNodeOutputs();
        
        if (mustReleaseLock)
            unlock();
    }
}
void AbstractAudioContext::handlePreRenderTasks()
{
    ASSERT(isAudioThread());

    // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
    // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
    if (tryLock()) {
        deferredTaskHandler().handleDeferredTasks();

        resolvePromisesForResume();

        // Check to see if source nodes can be stopped because the end time has passed.
        handleStoppableSourceNodes();

        unlock();
    }
}
void AbstractAudioContext::handlePostRenderTasks()
{
    ASSERT(isAudioThread());

    // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
    // from the render graph (in which case they'll render silence).
    if (tryLock()) {
        // Take care of AudioNode tasks where the tryLock() failed previously.
        deferredTaskHandler().breakConnections();

        // Dynamically clean up nodes which are no longer needed.
        releaseFinishedSourceNodes();

        deferredTaskHandler().handleDeferredTasks();
        deferredTaskHandler().requestToDeleteHandlersOnMainThread();

        unlock();
    }
}
Пример #25
0
void AudioContext::addDeferredFinishDeref(AudioNode* node, AudioNode::RefType refType)
{
    ASSERT(isAudioThread());
    m_deferredFinishDerefList.append(AudioContext::RefInfo(node, refType));
}
Пример #26
0
void AudioContext::addDeferredFinishDeref(AudioNode* node)
{
    ASSERT(isAudioThread());
    m_deferredFinishDerefList.append(node);
}
void DeferredTaskHandler::lock()
{
    // Don't allow regular lock in real-time audio thread.
    ASSERT(!isAudioThread());
    m_contextGraphMutex.lock();
}
Пример #28
0
void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
{
    ASSERT(isAudioThread());
    m_finishedNodes.append(node);
}
Пример #29
0
void DeferredTaskHandler::addDeferredBreakConnection(AudioHandler& node)
{
    ASSERT(isAudioThread());
    m_deferredBreakConnectionList.append(&node);
}
Пример #30
0
void DeferredTaskHandler::processAutomaticPullNodes(size_t framesToProcess) {
  DCHECK(isAudioThread());

  for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i)
    m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess);
}