Commit message: None
CVE: None
Vulnerability description: None

Project: Chrome

AudioContext::AudioContext(Document* document)
    : ActiveDOMObject(document)
    , m_isStopScheduled(false)
    , m_isCleared(false)
    , m_isInitialized(false)
    , m_destinationNode(nullptr)
    , m_isResolvingResumePromises(false)
    , m_automaticPullNodesNeedUpdating(false)
    , m_connectionCount(0)
    , m_didInitializeContextGraphMutex(false)
    , m_audioThread(0)
    , m_isOfflineContext(false)
    , m_contextState(Suspended)
    , m_cachedSampleFrame(0)
{
    m_didInitializeContextGraphMutex = true;
    m_destinationNode = DefaultAudioDestinationNode::create(this);

    initialize();
#if DEBUG_AUDIONODE_REFERENCES
    fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext::s_hardwareContextCount);
#endif
}

Project: Chrome

AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
    : ActiveDOMObject(document)
    , m_isStopScheduled(false)
    , m_isCleared(false)
    , m_isInitialized(false)
    , m_destinationNode(nullptr)
    , m_isResolvingResumePromises(false)
    , m_automaticPullNodesNeedUpdating(false)
    , m_connectionCount(0)
    , m_didInitializeContextGraphMutex(false)
    , m_audioThread(0)
    , m_isOfflineContext(true)
    , m_contextState(Suspended)
    , m_cachedSampleFrame(0)
{
    m_didInitializeContextGraphMutex = true;
    m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
    if (m_renderTarget.get())
        m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());

    initialize();
}

Project: Chrome

void AudioContext::addAutomaticPullNode(AudioNode* node)
{
    ASSERT(isGraphOwner());

    if (!m_automaticPullNodes.contains(node)) {
        m_automaticPullNodes.add(node);
        m_automaticPullNodesNeedUpdating = true;
    }
}

Project: Chrome

void AudioContext::addChangedChannelCountMode(AudioNode* node)
{
    ASSERT(isGraphOwner());
    ASSERT(isMainThread());
    m_deferredCountModeChange.add(node);
}

Project: Chrome

void AudioContext::addDeferredBreakConnection(AudioNode& node)
{
    ASSERT(isAudioThread());
    m_deferredBreakConnectionList.append(&node);
}

Project: Chrome

size_t AudioContext::cachedSampleFrame() const
{
    ASSERT(isMainThread());

    return m_cachedSampleFrame;
}

Project: Chrome

void AudioContext::clear()
{
    m_liveAudioSummingJunctions.clear();
    m_liveNodes.clear();
    m_destinationNode.clear();
    m_isCleared = true;
}

Project: Chrome

AudioContext* AudioContext::create(Document& document, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());
    if (s_hardwareContextCount >= MaxHardwareContexts) {
        exceptionState.throwDOMException(
            SyntaxError,
            "number of hardware contexts reached maximum (" + String::number(MaxHardwareContexts) + ").");
        return 0;
    }

    AudioContext* audioContext = new AudioContext(&document);
    audioContext->suspendIfNeeded();
    return audioContext;
}

Project: Chrome

AnalyserNode* AudioContext::createAnalyser()
{
    ASSERT(isMainThread());
    return AnalyserNode::create(this, m_destinationNode->sampleRate());
}

Project: Chrome

BiquadFilterNode* AudioContext::createBiquadFilter()
{
    ASSERT(isMainThread());
    return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
}

Project: Chrome

AudioBuffer* AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
{
    return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate, exceptionState);
}

Project: Chrome

ChannelMergerNode* AudioContext::createChannelMerger(ExceptionState& exceptionState)
{
    const unsigned ChannelMergerDefaultNumberOfInputs = 6;
    return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionState);
}

Project: Chrome

ChannelMergerNode* AudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());

    ChannelMergerNode* node = ChannelMergerNode::create(this, m_destinationNode->sampleRate(), numberOfInputs);

    if (!node) {
        exceptionState.throwDOMException(
            IndexSizeError,
            "number of inputs (" + String::number(numberOfInputs)
            + ") must be between 1 and "
            + String::number(AudioContext::maxNumberOfChannels()) + ".");
        return 0;
    }

    return node;
}

Project: Chrome

ChannelSplitterNode* AudioContext::createChannelSplitter(ExceptionState& exceptionState)
{
    const unsigned ChannelSplitterDefaultNumberOfOutputs = 6;
    return createChannelSplitter(ChannelSplitterDefaultNumberOfOutputs, exceptionState);
}

Project: Chrome

ChannelSplitterNode* AudioContext::createChannelSplitter(size_t numberOfOutputs, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());

    ChannelSplitterNode* node = ChannelSplitterNode::create(this, m_destinationNode->sampleRate(), numberOfOutputs);

    if (!node) {
        exceptionState.throwDOMException(
            IndexSizeError,
            "number of outputs (" + String::number(numberOfOutputs)
            + ") must be between 1 and "
            + String::number(AudioContext::maxNumberOfChannels()) + ".");
        return 0;
    }

    return node;
}

Project: Chrome

ConvolverNode* AudioContext::createConvolver()
{
    ASSERT(isMainThread());
    return ConvolverNode::create(this, m_destinationNode->sampleRate());
}

Project: Chrome

DelayNode* AudioContext::createDelay(ExceptionState& exceptionState)
{
    const double defaultMaxDelayTime = 1;
    return createDelay(defaultMaxDelayTime, exceptionState);
}

Project: Chrome

DelayNode* AudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());
    DelayNode* node = DelayNode::create(this, m_destinationNode->sampleRate(), maxDelayTime, exceptionState);
    if (exceptionState.hadException())
        return 0;
    return node;
}

Project: Chrome

DynamicsCompressorNode* AudioContext::createDynamicsCompressor()
{
    ASSERT(isMainThread());
    return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
}

Project: Chrome

GainNode* AudioContext::createGain()
{
    ASSERT(isMainThread());
    return GainNode::create(this, m_destinationNode->sampleRate());
}

Project: Chrome

MediaElementAudioSourceNode* AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());
    if (!mediaElement) {
        exceptionState.throwDOMException(
            InvalidStateError,
            "invalid HTMLMedialElement.");
        return 0;
    }

    if (mediaElement->audioSourceNode()) {
        exceptionState.throwDOMException(
            InvalidStateError,
            "HTMLMediaElement already connected previously to a different MediaElementSourceNode.");
        return 0;
    }

    MediaElementAudioSourceNode* node = MediaElementAudioSourceNode::create(this, mediaElement);

    mediaElement->setAudioSourceNode(node);

    refNode(node); // context keeps reference until node is disconnected
    return node;
}

Project: Chrome

MediaStreamAudioDestinationNode* AudioContext::createMediaStreamDestination()
{
    return MediaStreamAudioDestinationNode::create(this, 2);
}

Project: Chrome

MediaStreamAudioSourceNode* AudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());
    if (!mediaStream) {
        exceptionState.throwDOMException(
            InvalidStateError,
            "invalid MediaStream source");
        return 0;
    }

    MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks();
    if (audioTracks.isEmpty()) {
        exceptionState.throwDOMException(
            InvalidStateError,
            "MediaStream has no audio track");
        return 0;
    }

    MediaStreamTrack* audioTrack = audioTracks[0];
    OwnPtr<AudioSourceProvider> provider = audioTrack->createWebAudioSource();
    MediaStreamAudioSourceNode* node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack, provider.release());

    node->setFormat(2, sampleRate());

    refNode(node); // context keeps reference until node is disconnected
    return node;
}

Project: Chrome

OscillatorNode* AudioContext::createOscillator()
{
    ASSERT(isMainThread());

    OscillatorNode* node = OscillatorNode::create(this, m_destinationNode->sampleRate());


    return node;
}

Project: Chrome

PannerNode* AudioContext::createPanner()
{
    ASSERT(isMainThread());
    return PannerNode::create(this, m_destinationNode->sampleRate());
}

Project: Chrome

PeriodicWave* AudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());

    if (!real) {
        exceptionState.throwDOMException(
            SyntaxError,
            "invalid real array");
        return 0;
    }

    if (!imag) {
        exceptionState.throwDOMException(
            SyntaxError,
            "invalid imaginary array");
        return 0;
    }

    if (real->length() != imag->length()) {
        exceptionState.throwDOMException(
            IndexSizeError,
            "length of real array (" + String::number(real->length())
            + ") and length of imaginary array (" +  String::number(imag->length())
            + ") must match.");
        return 0;
    }

    if (real->length() > 4096) {
        exceptionState.throwDOMException(
            IndexSizeError,
            "length of real array (" + String::number(real->length())
            + ") exceeds allowed maximum of 4096");
        return 0;
    }

    if (imag->length() > 4096) {
        exceptionState.throwDOMException(
            IndexSizeError,
            "length of imaginary array (" + String::number(imag->length())
            + ") exceeds allowed maximum of 4096");
        return 0;
    }

    return PeriodicWave::create(sampleRate(), real, imag);
}

Project: Chrome

ScriptProcessorNode* AudioContext::createScriptProcessor(ExceptionState& exceptionState)
{
    return createScriptProcessor(0, 2, 2, exceptionState);
}

Project: Chrome

ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, ExceptionState& exceptionState)
{
    return createScriptProcessor(bufferSize, 2, 2, exceptionState);
}

Project: Chrome

ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState)
{
    ASSERT(isMainThread());
    ScriptProcessorNode* node = ScriptProcessorNode::create(this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);

    if (!node) {
        if (!numberOfInputChannels && !numberOfOutputChannels) {
            exceptionState.throwDOMException(
                IndexSizeError,
                "number of input channels and output channels cannot both be zero.");
        } else if (numberOfInputChannels > AudioContext::maxNumberOfChannels()) {
            exceptionState.throwDOMException(
                IndexSizeError,
                "number of input channels (" + String::number(numberOfInputChannels)
                + ") exceeds maximum ("
                + String::number(AudioContext::maxNumberOfChannels()) + ").");
        } else if (numberOfOutputChannels > AudioContext::maxNumberOfChannels()) {
            exceptionState.throwDOMException(
                IndexSizeError,
                "number of output channels (" + String::number(numberOfInputChannels)
                + ") exceeds maximum ("
                + String::number(AudioContext::maxNumberOfChannels()) + ").");
        } else {
            exceptionState.throwDOMException(
                IndexSizeError,
                "buffer size (" + String::number(bufferSize)
                + ") must be a power of two between 256 and 16384.");
        }
        return 0;
    }

    refNode(node); // context keeps reference until we stop making javascript rendering callbacks
    return node;
}

Project: Chrome

WaveShaperNode* AudioContext::createWaveShaper()
{
    ASSERT(isMainThread());
    return WaveShaperNode::create(this);
}

Project: Chrome

void AudioContext::decodeAudioData(DOMArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionState& exceptionState)
{
    if (!audioData) {
        exceptionState.throwDOMException(
            SyntaxError,
            "invalid ArrayBuffer for audioData.");
        return;
    }
    m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback);
}

Project: Chrome

void AudioContext::derefFinishedSourceNodes()
{
    ASSERT(isGraphOwner());
    ASSERT(isAudioThread());
    for (unsigned i = 0; i < m_finishedNodes.size(); i++)
        derefNode(m_finishedNodes[i]);

    m_finishedNodes.clear();
}

Project: Chrome

void AudioContext::derefNode(AudioNode* node)
{
    ASSERT(isGraphOwner());

    for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
        if (node == m_referencedNodes.at(i).get()) {
            node->breakConnection();
            m_referencedNodes.remove(i);
            break;
        }
    }
}

Project: Chrome

void AudioContext::derefUnfinishedSourceNodes()
{
    ASSERT(isMainThread());
    for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
        m_referencedNodes.at(i)->breakConnection();

    m_referencedNodes.clear();
}

Project: Chrome

void AudioContext::disposeOutputs(AudioNode& node)
{
    ASSERT(isGraphOwner());
    ASSERT(isMainThread());
    for (unsigned i = 0; i < node.numberOfOutputs(); ++i)
        node.output(i)->dispose();
}

Project: Chrome

ExecutionContext* AudioContext::executionContext() const
{
    return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext();
}

Project: Chrome

void AudioContext::fireCompletionEvent()
{
    ASSERT(isMainThread());
    if (!isMainThread())
        return;

    AudioBuffer* renderedBuffer = m_renderTarget.get();

    setContextState(Closed);

    ASSERT(renderedBuffer);
    if (!renderedBuffer)
        return;

    if (executionContext()) {
        dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
        m_offlineResolver->resolve(renderedBuffer);
    }
}

Project: Chrome

void AudioContext::handleDeferredAudioNodeTasks()
{
    ASSERT(isAudioThread() && isGraphOwner());

    for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i)
        m_deferredBreakConnectionList[i]->breakConnectionWithLock();
    m_deferredBreakConnectionList.clear();
}

Project: Chrome

void AudioContext::handleDirtyAudioNodeOutputs()
{
    ASSERT(isGraphOwner());

    for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
        (*i)->updateRenderingState();

    m_dirtyAudioNodeOutputs.clear();
}

Project: Chrome

void AudioContext::handleDirtyAudioSummingJunctions()
{
    ASSERT(isGraphOwner());

    for (HashSet<AudioSummingJunction*>::iterator i = m_dirtySummingJunctions.begin(); i != m_dirtySummingJunctions.end(); ++i)
        (*i)->updateRenderingState();

    m_dirtySummingJunctions.clear();
}

Project: Chrome

void AudioContext::handlePostRenderTasks()
{
    ASSERT(isAudioThread());

    if (tryLock()) {
        updateChangedChannelCountMode();

        handleDeferredAudioNodeTasks();

        derefFinishedSourceNodes();

        handleDirtyAudioSummingJunctions();
        handleDirtyAudioNodeOutputs();

        updateAutomaticPullNodes();
        resolvePromisesForSuspend();

        unlock();
    }
}

Project: Chrome

void AudioContext::handlePreRenderTasks()
{
    ASSERT(isAudioThread());

    if (tryLock()) {
        updateChangedChannelCountMode();

        handleDirtyAudioSummingJunctions();
        handleDirtyAudioNodeOutputs();

        updateAutomaticPullNodes();
        resolvePromisesForResume();

        handleStoppableSourceNodes();

        m_cachedSampleFrame = currentSampleFrame();

        unlock();
    }
}

Project: Chrome

void AudioContext::handleStoppableSourceNodes()
{
    ASSERT(isGraphOwner());

    for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
        AudioNode* node = m_referencedNodes.at(i).get();

        if (node->nodeType() == AudioNode::NodeTypeAudioBufferSource) {
            AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNode*>(node);
            sourceNode->handleStoppableSourceNode();
        }
    }
}

Project: Chrome

bool AudioContext::hasPendingActivity() const
{
    return !m_isCleared;
}

Project: Chrome

void AudioContext::initialize()
{
    if (isInitialized())
        return;

    FFTFrame::initialize();
    m_listener = AudioListener::create();

    if (m_destinationNode.get()) {
        m_destinationNode->initialize();

        if (!isOfflineContext()) {
            startRendering();
            ++s_hardwareContextCount;
        }

        m_isInitialized = true;
    }
}

Project: Chrome

const AtomicString& AudioContext::interfaceName() const
{
    return EventTargetNames::AudioContext;
}

Project: Chrome

bool AudioContext::isAudioThread() const
{
    return currentThread() == m_audioThread;
}

Project: Chrome

void AudioContext::lock()
{
    ASSERT(isMainThread());
    m_contextGraphMutex.lock();
}

Project: Chrome

void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
{
    ASSERT(isGraphOwner());
    ASSERT(isMainThread());
    m_dirtyAudioNodeOutputs.add(output);
}

Project: Chrome

void AudioContext::markSummingJunctionDirty(AudioSummingJunction* summingJunction)
{
    ASSERT(isGraphOwner());
    m_dirtySummingJunctions.add(summingJunction);
}

Project: Chrome

void AudioContext::notifyNodeStartedProcessing(AudioNode* node)
{
    refNode(node);
}

Project: Chrome

void AudioContext::notifyStateChange()
{
    dispatchEvent(Event::create(EventTypeNames::statechange));
}

Project: Chrome

void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
{
    ASSERT(isAudioThread());

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

Project: Chrome

void AudioContext::refNode(AudioNode* node)
{
    ASSERT(isMainThread());
    AutoLocker locker(this);

    m_referencedNodes.append(node);
    node->makeConnection();
}

Project: Chrome

void AudioContext::registerLiveAudioSummingJunction(AudioSummingJunction& junction)
{
    ASSERT(isMainThread());
    m_liveAudioSummingJunctions.add(&junction, adoptPtr(new AudioSummingJunctionDisposer(junction)));
}

Project: Chrome

void AudioContext::registerLiveNode(AudioNode& node)
{
    ASSERT(isMainThread());
    m_liveNodes.add(&node, adoptPtr(new AudioNodeDisposer(node)));
}

Project: Chrome

void AudioContext::rejectPendingResolvers()
{
    ASSERT(isMainThread());


    for (auto& resolver : m_suspendResolvers) {
        resolver->reject(DOMException::create(InvalidStateError, "Audio context is going away"));
    }
    m_suspendResolvers.clear();

    for (auto& resolver : m_resumeResolvers) {
        resolver->reject(DOMException::create(InvalidStateError, "Audio context is going away"));
    }
    m_resumeResolvers.clear();
    m_isResolvingResumePromises = false;
}

Project: Chrome

void AudioContext::removeChangedChannelCountMode(AudioNode* node)
{
    ASSERT(isGraphOwner());

    m_deferredCountModeChange.remove(node);
}

Project: Chrome

void AudioContext::removeMarkedAudioNodeOutput(AudioNodeOutput* output)
{
    ASSERT(isGraphOwner());
    ASSERT(isMainThread());
    m_dirtyAudioNodeOutputs.remove(output);
}

Project: Chrome

void AudioContext::removeMarkedSummingJunction(AudioSummingJunction* summingJunction)
{
    ASSERT(isMainThread());
    AutoLocker locker(this);
    m_dirtySummingJunctions.remove(summingJunction);
}

Project: Chrome

void AudioContext::resolvePromisesForResume()
{
    ASSERT(isAudioThread());
    ASSERT(isGraphOwner());

    if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) {
        m_isResolvingResumePromises = true;
        callOnMainThread(bind(&AudioContext::resolvePromisesForResumeOnMainThread, this));
    }
}

Project: Chrome

void AudioContext::resolvePromisesForResumeOnMainThread()
{
    ASSERT(isMainThread());
    AutoLocker locker(this);

    for (auto& resolver : m_resumeResolvers) {
        if (m_contextState == Closed) {
            resolver->reject(
                DOMException::create(InvalidStateError, "Cannot resume a context that has been closed"));
        } else {
            resolver->resolve();
        }
    }

    m_resumeResolvers.clear();
    m_isResolvingResumePromises = false;
}

Project: Chrome

void AudioContext::resolvePromisesForSuspend()
{
    ASSERT(isAudioThread());
    ASSERT(isGraphOwner());

    if (m_suspendResolvers.size() > 0)
        callOnMainThread(bind(&AudioContext::resolvePromisesForSuspendOnMainThread, this));

}

Project: Chrome

void AudioContext::resolvePromisesForSuspendOnMainThread()
{
    ASSERT(isMainThread());
    AutoLocker locker(this);

    if (m_destinationNode)
        stopRendering();

    for (auto& resolver : m_suspendResolvers) {
        if (m_contextState == Closed) {
            resolver->reject(
                DOMException::create(InvalidStateError, "Cannot suspend a context that has been closed"));
        } else {
            resolver->resolve();
        }
    }

    m_suspendResolvers.clear();
}

Project: Chrome

ScriptPromise AudioContext::resumeContext(ScriptState* scriptState)
{
    ASSERT(isMainThread());
    AutoLocker locker(this);

    if (isOfflineContext()) {
        return ScriptPromise::rejectWithDOMException(
            scriptState,
            DOMException::create(
                InvalidStateError,
                "cannot resume an OfflineAudioContext"));
    }

    RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    if (m_destinationNode)
        startRendering();

    m_resumeResolvers.append(resolver);

    return promise;
}

Project: Chrome

void AudioContext::setContextState(AudioContextState newState)
{
    ASSERT(isMainThread());

    switch (newState) {
    case Suspended:
        ASSERT(m_contextState == Running);
        break;
    case Running:
        ASSERT(m_contextState == Suspended);
        break;
    case Closed:
        ASSERT(m_contextState != Closed);
        break;
    }

    if (newState == m_contextState) {
        return;
    }

    m_contextState = newState;

    if (executionContext())
        executionContext()->postTask(createSameThreadTask(&AudioContext::notifyStateChange, this));
}

Project: Chrome

void AudioContext::startRendering()
{
    ASSERT(isMainThread());
    ASSERT(m_destinationNode);

    if (m_contextState == Suspended) {
        destination()->startRendering();
        setContextState(Running);
    }
}

Project: Chrome

String AudioContext::state() const
{
    switch (m_contextState) {
    case Suspended:
        return "suspended";
    case Running:
        return "running";
    case Closed:
        return "closed";
    }
    ASSERT_NOT_REACHED();
    return "";
}

Project: Chrome

void AudioContext::stop()
{
    if (m_isStopScheduled)
        return;
    m_isStopScheduled = true;

    callOnMainThread(bind(&AudioContext::uninitialize, this));
}

Project: Chrome

void AudioContext::stopRendering()
{
    ASSERT(isMainThread());
    ASSERT(m_destinationNode);
    ASSERT(!isOfflineContext());

    if (m_contextState == Running) {
        destination()->stopRendering();
        setContextState(Suspended);
    }
}

Project: Chrome

ScriptPromise AudioContext::suspendContext(ScriptState* scriptState)
{
    ASSERT(isMainThread());
    AutoLocker locker(this);

    if (isOfflineContext()) {
        return ScriptPromise::rejectWithDOMException(
            scriptState,
            DOMException::create(
                InvalidStateError,
                "cannot suspend an OfflineAudioContext"));
    }

    RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
    ScriptPromise promise = resolver->promise();

    m_suspendResolvers.append(resolver);

    return promise;
}

Project: Chrome

void AudioContext::trace(Visitor* visitor)
{
    visitor->trace(m_offlineResolver);
    visitor->trace(m_renderTarget);
    visitor->trace(m_destinationNode);
    visitor->trace(m_listener);
    if (m_didInitializeContextGraphMutex) {
        AutoLocker lock(this);
        visitor->trace(m_referencedNodes);
    } else {
        visitor->trace(m_referencedNodes);
    }
    visitor->trace(m_resumeResolvers);
    visitor->trace(m_suspendResolvers);
    visitor->trace(m_liveNodes);
    visitor->trace(m_liveAudioSummingJunctions);
    RefCountedGarbageCollectedEventTargetWithInlineData<AudioContext>::trace(visitor);
    ActiveDOMObject::trace(visitor);
}

Project: Chrome

bool AudioContext::tryLock()
{
    ASSERT(isAudioThread());
    if (!isAudioThread()) {
        lock();
        return true;
    }
    return m_contextGraphMutex.tryLock();
}

Project: Chrome

void AudioContext::uninitialize()
{
    ASSERT(isMainThread());

    if (!isInitialized())
        return;

    m_isInitialized = false;

    m_destinationNode->uninitialize();

    if (!isOfflineContext()) {
        ASSERT(s_hardwareContextCount);
        --s_hardwareContextCount;
    }

    derefUnfinishedSourceNodes();

    rejectPendingResolvers();

    ASSERT(m_listener);
    m_listener->waitForHRTFDatabaseLoaderThreadCompletion();

    clear();
}

Project: Chrome

void AudioContext::unlock()
{
    m_contextGraphMutex.unlock();
}

Project: Chrome

void AudioContext::updateAutomaticPullNodes()
{
    ASSERT(isGraphOwner());

    if (m_automaticPullNodesNeedUpdating) {
        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());

        unsigned j = 0;
        for (HashSet<AudioNode*>::iterator i = m_automaticPullNodes.begin(); i != m_automaticPullNodes.end(); ++i, ++j) {
            AudioNode* output = *i;
            m_renderingAutomaticPullNodes[j] = output;
        }

        m_automaticPullNodesNeedUpdating = false;
    }
}

Project: Chrome

void AudioContext::updateChangedChannelCountMode()
{
    ASSERT(isGraphOwner());

    for (HashSet<AudioNode*>::iterator k = m_deferredCountModeChange.begin(); k != m_deferredCountModeChange.end(); ++k)
        (*k)->updateChannelCountMode();

     m_deferredCountModeChange.clear();
 }

Project: Chrome

AudioContext::~AudioContext()
{
#if DEBUG_AUDIONODE_REFERENCES
    fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this);
#endif
    ASSERT(!m_isInitialized);
    ASSERT(!m_referencedNodes.size());
    ASSERT(!m_finishedNodes.size());
    ASSERT(!m_automaticPullNodes.size());
    if (m_automaticPullNodesNeedUpdating)
        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
    ASSERT(!m_renderingAutomaticPullNodes.size());
    ASSERT(!m_suspendResolvers.size());
    ASSERT(!m_resumeResolvers.size());
}

Project: Chrome

AudioContext::AudioNodeDisposer::~AudioNodeDisposer()
{
    ASSERT(isMainThread());
    AudioContext::AutoLocker locker(m_node.context());
    m_node.dispose();
}

Project: Chrome

AudioContext::AudioSummingJunctionDisposer::~AudioSummingJunctionDisposer()
{
    ASSERT(isMainThread());
    m_junction.dispose();
}

Project: Chrome

MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* context, HTMLMediaElement* mediaElement)
    : AudioSourceNode(NodeTypeMediaElementAudioSource, context, context->sampleRate())
    , m_mediaElement(mediaElement)
    , m_sourceNumberOfChannels(0)
    , m_sourceSampleRate(0)
{
    addOutput(AudioNodeOutput::create(this, 2));

    initialize();
}

Project: Chrome

void MediaElementAudioSourceNode::dispose()
{
    m_mediaElement->setAudioSourceNode(0);
    uninitialize();
    AudioSourceNode::dispose();
}

Project: Chrome

void MediaElementAudioSourceNode::lock()
{
    m_processLock.lock();
}

Project: Chrome

void MediaElementAudioSourceNode::setFormat(size_t numberOfChannels, float sourceSampleRate)
{
    if (numberOfChannels != m_sourceNumberOfChannels || sourceSampleRate != m_sourceSampleRate) {
        if (!numberOfChannels || numberOfChannels > AudioContext::maxNumberOfChannels() || !AudioUtilities::isValidAudioBufferSampleRate(sourceSampleRate)) {
            WTF_LOG(Media, "MediaElementAudioSourceNode::setFormat(%u, %f) - unhandled format change", static_cast<unsigned>(numberOfChannels), sourceSampleRate);
            m_sourceNumberOfChannels = 0;
            m_sourceSampleRate = 0;
            return;
        }

        m_sourceNumberOfChannels = numberOfChannels;
        m_sourceSampleRate = sourceSampleRate;

        Locker<MediaElementAudioSourceNode> locker(*this);

        if (sourceSampleRate != sampleRate()) {
            double scaleFactor = sourceSampleRate / sampleRate();
            m_multiChannelResampler = adoptPtr(new MultiChannelResampler(scaleFactor, numberOfChannels));
        } else {
            m_multiChannelResampler.clear();
        }

        {
            AudioContext::AutoLocker contextLocker(context());

            output(0)->setNumberOfChannels(numberOfChannels);
        }
    }
}

Project: Chrome

void MediaElementAudioSourceNode::trace(Visitor* visitor)
{
    visitor->trace(m_mediaElement);
    AudioSourceNode::trace(visitor);
    AudioSourceProviderClient::trace(visitor);
}

Project: Chrome

void MediaElementAudioSourceNode::unlock()
{
    m_processLock.unlock();
}