1/*
2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26
27#if ENABLE(WEB_AUDIO)
28
29#include "modules/webaudio/AudioContext.h"
30
31#include "bindings/core/v8/ExceptionMessages.h"
32#include "bindings/core/v8/ExceptionState.h"
33#include "core/dom/Document.h"
34#include "core/dom/ExceptionCode.h"
35#include "core/html/HTMLMediaElement.h"
36#include "core/inspector/ScriptCallStack.h"
37#include "platform/audio/FFTFrame.h"
38#include "platform/audio/HRTFPanner.h"
39#include "modules/mediastream/MediaStream.h"
40#include "modules/webaudio/AnalyserNode.h"
41#include "modules/webaudio/AudioBuffer.h"
42#include "modules/webaudio/AudioBufferCallback.h"
43#include "modules/webaudio/AudioBufferSourceNode.h"
44#include "modules/webaudio/AudioListener.h"
45#include "modules/webaudio/AudioNodeInput.h"
46#include "modules/webaudio/AudioNodeOutput.h"
47#include "modules/webaudio/BiquadFilterNode.h"
48#include "modules/webaudio/ChannelMergerNode.h"
49#include "modules/webaudio/ChannelSplitterNode.h"
50#include "modules/webaudio/ConvolverNode.h"
51#include "modules/webaudio/DefaultAudioDestinationNode.h"
52#include "modules/webaudio/DelayNode.h"
53#include "modules/webaudio/DynamicsCompressorNode.h"
54#include "modules/webaudio/GainNode.h"
55#include "modules/webaudio/MediaElementAudioSourceNode.h"
56#include "modules/webaudio/MediaStreamAudioDestinationNode.h"
57#include "modules/webaudio/MediaStreamAudioSourceNode.h"
58#include "modules/webaudio/OfflineAudioCompletionEvent.h"
59#include "modules/webaudio/OfflineAudioContext.h"
60#include "modules/webaudio/OfflineAudioDestinationNode.h"
61#include "modules/webaudio/OscillatorNode.h"
62#include "modules/webaudio/PannerNode.h"
63#include "modules/webaudio/PeriodicWave.h"
64#include "modules/webaudio/ScriptProcessorNode.h"
65#include "modules/webaudio/WaveShaperNode.h"
66
67#if DEBUG_AUDIONODE_REFERENCES
68#include <stdio.h>
69#endif
70
71#include "wtf/ArrayBuffer.h"
72#include "wtf/Atomics.h"
73#include "wtf/PassOwnPtr.h"
74#include "wtf/text/WTFString.h"
75
76// FIXME: check the proper way to reference an undefined thread ID
77const WTF::ThreadIdentifier UndefinedThreadIdentifier = 0xffffffff;
78
79namespace blink {
80
81// Don't allow more than this number of simultaneous AudioContexts talking to hardware.
82const unsigned MaxHardwareContexts = 6;
83unsigned AudioContext::s_hardwareContextCount = 0;
84
85AudioContext* AudioContext::create(Document& document, ExceptionState& exceptionState)
86{
87    ASSERT(isMainThread());
88    if (s_hardwareContextCount >= MaxHardwareContexts) {
89        exceptionState.throwDOMException(
90            SyntaxError,
91            "number of hardware contexts reached maximum (" + String::number(MaxHardwareContexts) + ").");
92        return 0;
93    }
94
95    AudioContext* audioContext = adoptRefCountedGarbageCollectedWillBeNoop(new AudioContext(&document));
96    audioContext->suspendIfNeeded();
97    return audioContext;
98}
99
100// Constructor for rendering to the audio hardware.
101AudioContext::AudioContext(Document* document)
102    : ActiveDOMObject(document)
103    , m_isStopScheduled(false)
104    , m_isCleared(false)
105    , m_isInitialized(false)
106    , m_destinationNode(nullptr)
107    , m_automaticPullNodesNeedUpdating(false)
108    , m_connectionCount(0)
109    , m_audioThread(0)
110    , m_graphOwnerThread(UndefinedThreadIdentifier)
111    , m_isOfflineContext(false)
112{
113    m_destinationNode = DefaultAudioDestinationNode::create(this);
114
115    initialize();
116#if DEBUG_AUDIONODE_REFERENCES
117    fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext::s_hardwareContextCount);
118#endif
119}
120
121// Constructor for offline (non-realtime) rendering.
122AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
123    : ActiveDOMObject(document)
124    , m_isStopScheduled(false)
125    , m_isCleared(false)
126    , m_isInitialized(false)
127    , m_destinationNode(nullptr)
128    , m_automaticPullNodesNeedUpdating(false)
129    , m_connectionCount(0)
130    , m_audioThread(0)
131    , m_graphOwnerThread(UndefinedThreadIdentifier)
132    , m_isOfflineContext(true)
133{
134    // Create a new destination for offline rendering.
135    m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
136    if (m_renderTarget.get())
137        m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());
138
139    initialize();
140}
141
142AudioContext::~AudioContext()
143{
144#if DEBUG_AUDIONODE_REFERENCES
145    fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this);
146#endif
147    // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
148    ASSERT(!m_isInitialized);
149    ASSERT(!m_referencedNodes.size());
150    ASSERT(!m_finishedNodes.size());
151    ASSERT(!m_automaticPullNodes.size());
152    if (m_automaticPullNodesNeedUpdating)
153        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
154    ASSERT(!m_renderingAutomaticPullNodes.size());
155}
156
157void AudioContext::initialize()
158{
159    if (isInitialized())
160        return;
161
162    FFTFrame::initialize();
163    m_listener = AudioListener::create();
164
165    if (m_destinationNode.get()) {
166        m_destinationNode->initialize();
167
168        if (!isOfflineContext()) {
169            // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
170            // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
171            // NOTE: for now default AudioContext does not need an explicit startRendering() call from JavaScript.
172            // We may want to consider requiring it for symmetry with OfflineAudioContext.
173            m_destinationNode->startRendering();
174            ++s_hardwareContextCount;
175        }
176
177        m_isInitialized = true;
178    }
179}
180
181void AudioContext::clear()
182{
183    // We need to run disposers before destructing m_contextGraphMutex.
184    m_liveAudioSummingJunctions.clear();
185    m_liveNodes.clear();
186    m_destinationNode.clear();
187    m_isCleared = true;
188}
189
190void AudioContext::uninitialize()
191{
192    ASSERT(isMainThread());
193
194    if (!isInitialized())
195        return;
196
197    // This stops the audio thread and all audio rendering.
198    m_destinationNode->uninitialize();
199
200    if (!isOfflineContext()) {
201        ASSERT(s_hardwareContextCount);
202        --s_hardwareContextCount;
203    }
204
205    // Get rid of the sources which may still be playing.
206    derefUnfinishedSourceNodes();
207
208    m_isInitialized = false;
209    ASSERT(m_listener);
210    m_listener->waitForHRTFDatabaseLoaderThreadCompletion();
211
212    clear();
213}
214
215void AudioContext::stop()
216{
217    // Usually ExecutionContext calls stop twice.
218    if (m_isStopScheduled)
219        return;
220    m_isStopScheduled = true;
221
222    // Don't call uninitialize() immediately here because the ExecutionContext is in the middle
223    // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
224    // ActiveDOMObjects so let's schedule uninitialize() to be called later.
225    // FIXME: see if there's a more direct way to handle this issue.
226    callOnMainThread(bind(&AudioContext::uninitialize, this));
227}
228
229bool AudioContext::hasPendingActivity() const
230{
231    // According to spec AudioContext must die only after page navigates.
232    return !m_isCleared;
233}
234
235AudioBuffer* AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
236{
237    return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate, exceptionState);
238}
239
240void AudioContext::decodeAudioData(ArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionState& exceptionState)
241{
242    if (!audioData) {
243        exceptionState.throwDOMException(
244            SyntaxError,
245            "invalid ArrayBuffer for audioData.");
246        return;
247    }
248    m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback);
249}
250
251AudioBufferSourceNode* AudioContext::createBufferSource()
252{
253    ASSERT(isMainThread());
254    AudioBufferSourceNode* node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
255
256    // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
257    // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
258    refNode(node);
259
260    return node;
261}
262
263MediaElementAudioSourceNode* AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState)
264{
265    ASSERT(isMainThread());
266    if (!mediaElement) {
267        exceptionState.throwDOMException(
268            InvalidStateError,
269            "invalid HTMLMedialElement.");
270        return 0;
271    }
272
273    // First check if this media element already has a source node.
274    if (mediaElement->audioSourceNode()) {
275        exceptionState.throwDOMException(
276            InvalidStateError,
277            "invalid HTMLMediaElement.");
278        return 0;
279    }
280
281    MediaElementAudioSourceNode* node = MediaElementAudioSourceNode::create(this, mediaElement);
282
283    mediaElement->setAudioSourceNode(node);
284
285    refNode(node); // context keeps reference until node is disconnected
286    return node;
287}
288
289MediaStreamAudioSourceNode* AudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState)
290{
291    ASSERT(isMainThread());
292    if (!mediaStream) {
293        exceptionState.throwDOMException(
294            InvalidStateError,
295            "invalid MediaStream source");
296        return 0;
297    }
298
299    MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks();
300    if (audioTracks.isEmpty()) {
301        exceptionState.throwDOMException(
302            InvalidStateError,
303            "MediaStream has no audio track");
304        return 0;
305    }
306
307    // Use the first audio track in the media stream.
308    MediaStreamTrack* audioTrack = audioTracks[0];
309    OwnPtr<AudioSourceProvider> provider = audioTrack->createWebAudioSource();
310    MediaStreamAudioSourceNode* node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack, provider.release());
311
312    // FIXME: Only stereo streams are supported right now. We should be able to accept multi-channel streams.
313    node->setFormat(2, sampleRate());
314
315    refNode(node); // context keeps reference until node is disconnected
316    return node;
317}
318
319MediaStreamAudioDestinationNode* AudioContext::createMediaStreamDestination()
320{
321    // Set number of output channels to stereo by default.
322    return MediaStreamAudioDestinationNode::create(this, 2);
323}
324
325ScriptProcessorNode* AudioContext::createScriptProcessor(ExceptionState& exceptionState)
326{
327    // Set number of input/output channels to stereo by default.
328    return createScriptProcessor(0, 2, 2, exceptionState);
329}
330
331ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, ExceptionState& exceptionState)
332{
333    // Set number of input/output channels to stereo by default.
334    return createScriptProcessor(bufferSize, 2, 2, exceptionState);
335}
336
337ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState& exceptionState)
338{
339    // Set number of output channels to stereo by default.
340    return createScriptProcessor(bufferSize, numberOfInputChannels, 2, exceptionState);
341}
342
343ScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState)
344{
345    ASSERT(isMainThread());
346    ScriptProcessorNode* node = ScriptProcessorNode::create(this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
347
348    if (!node) {
349        if (!numberOfInputChannels && !numberOfOutputChannels) {
350            exceptionState.throwDOMException(
351                IndexSizeError,
352                "number of input channels and output channels cannot both be zero.");
353        } else if (numberOfInputChannels > AudioContext::maxNumberOfChannels()) {
354            exceptionState.throwDOMException(
355                IndexSizeError,
356                "number of input channels (" + String::number(numberOfInputChannels)
357                + ") exceeds maximum ("
358                + String::number(AudioContext::maxNumberOfChannels()) + ").");
359        } else if (numberOfOutputChannels > AudioContext::maxNumberOfChannels()) {
360            exceptionState.throwDOMException(
361                IndexSizeError,
362                "number of output channels (" + String::number(numberOfInputChannels)
363                + ") exceeds maximum ("
364                + String::number(AudioContext::maxNumberOfChannels()) + ").");
365        } else {
366            exceptionState.throwDOMException(
367                IndexSizeError,
368                "buffer size (" + String::number(bufferSize)
369                + ") must be a power of two between 256 and 16384.");
370        }
371        return 0;
372    }
373
374    refNode(node); // context keeps reference until we stop making javascript rendering callbacks
375    return node;
376}
377
378BiquadFilterNode* AudioContext::createBiquadFilter()
379{
380    ASSERT(isMainThread());
381    return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
382}
383
384WaveShaperNode* AudioContext::createWaveShaper()
385{
386    ASSERT(isMainThread());
387    return WaveShaperNode::create(this);
388}
389
390PannerNode* AudioContext::createPanner()
391{
392    ASSERT(isMainThread());
393    return PannerNode::create(this, m_destinationNode->sampleRate());
394}
395
396ConvolverNode* AudioContext::createConvolver()
397{
398    ASSERT(isMainThread());
399    return ConvolverNode::create(this, m_destinationNode->sampleRate());
400}
401
402DynamicsCompressorNode* AudioContext::createDynamicsCompressor()
403{
404    ASSERT(isMainThread());
405    return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
406}
407
408AnalyserNode* AudioContext::createAnalyser()
409{
410    ASSERT(isMainThread());
411    return AnalyserNode::create(this, m_destinationNode->sampleRate());
412}
413
414GainNode* AudioContext::createGain()
415{
416    ASSERT(isMainThread());
417    return GainNode::create(this, m_destinationNode->sampleRate());
418}
419
420DelayNode* AudioContext::createDelay(ExceptionState& exceptionState)
421{
422    const double defaultMaxDelayTime = 1;
423    return createDelay(defaultMaxDelayTime, exceptionState);
424}
425
426DelayNode* AudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState)
427{
428    ASSERT(isMainThread());
429    DelayNode* node = DelayNode::create(this, m_destinationNode->sampleRate(), maxDelayTime, exceptionState);
430    if (exceptionState.hadException())
431        return 0;
432    return node;
433}
434
435ChannelSplitterNode* AudioContext::createChannelSplitter(ExceptionState& exceptionState)
436{
437    const unsigned ChannelSplitterDefaultNumberOfOutputs = 6;
438    return createChannelSplitter(ChannelSplitterDefaultNumberOfOutputs, exceptionState);
439}
440
441ChannelSplitterNode* AudioContext::createChannelSplitter(size_t numberOfOutputs, ExceptionState& exceptionState)
442{
443    ASSERT(isMainThread());
444
445    ChannelSplitterNode* node = ChannelSplitterNode::create(this, m_destinationNode->sampleRate(), numberOfOutputs);
446
447    if (!node) {
448        exceptionState.throwDOMException(
449            IndexSizeError,
450            "number of outputs (" + String::number(numberOfOutputs)
451            + ") must be between 1 and "
452            + String::number(AudioContext::maxNumberOfChannels()) + ".");
453        return 0;
454    }
455
456    return node;
457}
458
459ChannelMergerNode* AudioContext::createChannelMerger(ExceptionState& exceptionState)
460{
461    const unsigned ChannelMergerDefaultNumberOfInputs = 6;
462    return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionState);
463}
464
465ChannelMergerNode* AudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState)
466{
467    ASSERT(isMainThread());
468
469    ChannelMergerNode* node = ChannelMergerNode::create(this, m_destinationNode->sampleRate(), numberOfInputs);
470
471    if (!node) {
472        exceptionState.throwDOMException(
473            IndexSizeError,
474            "number of inputs (" + String::number(numberOfInputs)
475            + ") must be between 1 and "
476            + String::number(AudioContext::maxNumberOfChannels()) + ".");
477        return 0;
478    }
479
480    return node;
481}
482
483OscillatorNode* AudioContext::createOscillator()
484{
485    ASSERT(isMainThread());
486
487    OscillatorNode* node = OscillatorNode::create(this, m_destinationNode->sampleRate());
488
489    // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
490    // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
491    refNode(node);
492
493    return node;
494}
495
496PeriodicWave* AudioContext::createPeriodicWave(Float32Array* real, Float32Array* imag, ExceptionState& exceptionState)
497{
498    ASSERT(isMainThread());
499
500    if (!real) {
501        exceptionState.throwDOMException(
502            SyntaxError,
503            "invalid real array");
504        return 0;
505    }
506
507    if (!imag) {
508        exceptionState.throwDOMException(
509            SyntaxError,
510            "invalid imaginary array");
511        return 0;
512    }
513
514    if (real->length() != imag->length()) {
515        exceptionState.throwDOMException(
516            IndexSizeError,
517            "length of real array (" + String::number(real->length())
518            + ") and length of imaginary array (" +  String::number(imag->length())
519            + ") must match.");
520        return 0;
521    }
522
523    if (real->length() > 4096) {
524        exceptionState.throwDOMException(
525            IndexSizeError,
526            "length of real array (" + String::number(real->length())
527            + ") exceeds allowed maximum of 4096");
528        return 0;
529    }
530
531    if (imag->length() > 4096) {
532        exceptionState.throwDOMException(
533            IndexSizeError,
534            "length of imaginary array (" + String::number(imag->length())
535            + ") exceeds allowed maximum of 4096");
536        return 0;
537    }
538
539    return PeriodicWave::create(sampleRate(), real, imag);
540}
541
542void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
543{
544    ASSERT(isAudioThread());
545    m_finishedNodes.append(node);
546}
547
548void AudioContext::derefFinishedSourceNodes()
549{
550    ASSERT(isGraphOwner());
551    ASSERT(isAudioThread());
552    for (unsigned i = 0; i < m_finishedNodes.size(); i++)
553        derefNode(m_finishedNodes[i]);
554
555    m_finishedNodes.clear();
556}
557
558void AudioContext::refNode(AudioNode* node)
559{
560    ASSERT(isMainThread());
561    AutoLocker locker(this);
562
563    m_referencedNodes.append(node);
564    node->makeConnection();
565}
566
567void AudioContext::derefNode(AudioNode* node)
568{
569    ASSERT(isGraphOwner());
570
571    for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
572        if (node == m_referencedNodes[i].get()) {
573            node->breakConnection();
574            m_referencedNodes.remove(i);
575            break;
576        }
577    }
578}
579
580void AudioContext::derefUnfinishedSourceNodes()
581{
582    ASSERT(isMainThread());
583    for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
584        m_referencedNodes[i]->breakConnection();
585
586    m_referencedNodes.clear();
587}
588
589void AudioContext::lock(bool& mustReleaseLock)
590{
591    // Don't allow regular lock in real-time audio thread.
592    ASSERT(isMainThread());
593
594    ThreadIdentifier thisThread = currentThread();
595
596    if (thisThread == m_graphOwnerThread) {
597        // We already have the lock.
598        mustReleaseLock = false;
599    } else {
600        // Acquire the lock.
601        m_contextGraphMutex.lock();
602        m_graphOwnerThread = thisThread;
603        mustReleaseLock = true;
604    }
605}
606
607bool AudioContext::tryLock(bool& mustReleaseLock)
608{
609    ThreadIdentifier thisThread = currentThread();
610    bool isAudioThread = thisThread == audioThread();
611
612    // Try to catch cases of using try lock on main thread - it should use regular lock.
613    ASSERT(isAudioThread);
614
615    if (!isAudioThread) {
616        // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
617        lock(mustReleaseLock);
618        return true;
619    }
620
621    bool hasLock;
622
623    if (thisThread == m_graphOwnerThread) {
624        // Thread already has the lock.
625        hasLock = true;
626        mustReleaseLock = false;
627    } else {
628        // Don't already have the lock - try to acquire it.
629        hasLock = m_contextGraphMutex.tryLock();
630
631        if (hasLock)
632            m_graphOwnerThread = thisThread;
633
634        mustReleaseLock = hasLock;
635    }
636
637    return hasLock;
638}
639
640void AudioContext::unlock()
641{
642    ASSERT(currentThread() == m_graphOwnerThread);
643
644    m_graphOwnerThread = UndefinedThreadIdentifier;
645    m_contextGraphMutex.unlock();
646}
647
648bool AudioContext::isAudioThread() const
649{
650    return currentThread() == m_audioThread;
651}
652
653bool AudioContext::isGraphOwner() const
654{
655    return currentThread() == m_graphOwnerThread;
656}
657
658void AudioContext::addDeferredBreakConnection(AudioNode& node)
659{
660    ASSERT(isAudioThread());
661    m_deferredBreakConnectionList.append(&node);
662}
663
664void AudioContext::handlePreRenderTasks()
665{
666    ASSERT(isAudioThread());
667
668    // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
669    // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
670    bool mustReleaseLock;
671    if (tryLock(mustReleaseLock)) {
672        // Update the channel count mode.
673        updateChangedChannelCountMode();
674
675        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
676        handleDirtyAudioSummingJunctions();
677        handleDirtyAudioNodeOutputs();
678
679        updateAutomaticPullNodes();
680
681        if (mustReleaseLock)
682            unlock();
683    }
684}
685
686void AudioContext::handlePostRenderTasks()
687{
688    ASSERT(isAudioThread());
689
690    // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
691    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
692    // from the render graph (in which case they'll render silence).
693    bool mustReleaseLock;
694    if (tryLock(mustReleaseLock)) {
695        // Update the channel count mode.
696        updateChangedChannelCountMode();
697
698        // Take care of AudioNode tasks where the tryLock() failed previously.
699        handleDeferredAudioNodeTasks();
700
701        // Dynamically clean up nodes which are no longer needed.
702        derefFinishedSourceNodes();
703
704        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
705        handleDirtyAudioSummingJunctions();
706        handleDirtyAudioNodeOutputs();
707
708        updateAutomaticPullNodes();
709
710        if (mustReleaseLock)
711            unlock();
712    }
713}
714
715void AudioContext::handleDeferredAudioNodeTasks()
716{
717    ASSERT(isAudioThread() && isGraphOwner());
718
719    for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i)
720        m_deferredBreakConnectionList[i]->breakConnectionWithLock();
721    m_deferredBreakConnectionList.clear();
722}
723
724void AudioContext::registerLiveNode(AudioNode& node)
725{
726    ASSERT(isMainThread());
727    m_liveNodes.add(&node, adoptPtr(new AudioNodeDisposer(node)));
728}
729
730AudioContext::AudioNodeDisposer::~AudioNodeDisposer()
731{
732    ASSERT(isMainThread());
733    AudioContext::AutoLocker locker(m_node.context());
734    m_node.dispose();
735}
736
737void AudioContext::registerLiveAudioSummingJunction(AudioSummingJunction& junction)
738{
739    ASSERT(isMainThread());
740    m_liveAudioSummingJunctions.add(&junction, adoptPtr(new AudioSummingJunctionDisposer(junction)));
741}
742
743AudioContext::AudioSummingJunctionDisposer::~AudioSummingJunctionDisposer()
744{
745    ASSERT(isMainThread());
746    m_junction.dispose();
747}
748
749void AudioContext::disposeOutputs(AudioNode& node)
750{
751    ASSERT(isGraphOwner());
752    ASSERT(isMainThread());
753    for (unsigned i = 0; i < node.numberOfOutputs(); ++i)
754        node.output(i)->dispose();
755}
756
757void AudioContext::markSummingJunctionDirty(AudioSummingJunction* summingJunction)
758{
759    ASSERT(isGraphOwner());
760    m_dirtySummingJunctions.add(summingJunction);
761}
762
763void AudioContext::removeMarkedSummingJunction(AudioSummingJunction* summingJunction)
764{
765    ASSERT(isMainThread());
766    AutoLocker locker(this);
767    m_dirtySummingJunctions.remove(summingJunction);
768}
769
770void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
771{
772    ASSERT(isGraphOwner());
773    ASSERT(isMainThread());
774    m_dirtyAudioNodeOutputs.add(output);
775}
776
777void AudioContext::removeMarkedAudioNodeOutput(AudioNodeOutput* output)
778{
779    ASSERT(isGraphOwner());
780    ASSERT(isMainThread());
781    m_dirtyAudioNodeOutputs.remove(output);
782}
783
784void AudioContext::handleDirtyAudioSummingJunctions()
785{
786    ASSERT(isGraphOwner());
787
788    for (HashSet<AudioSummingJunction*>::iterator i = m_dirtySummingJunctions.begin(); i != m_dirtySummingJunctions.end(); ++i)
789        (*i)->updateRenderingState();
790
791    m_dirtySummingJunctions.clear();
792}
793
794void AudioContext::handleDirtyAudioNodeOutputs()
795{
796    ASSERT(isGraphOwner());
797
798    for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
799        (*i)->updateRenderingState();
800
801    m_dirtyAudioNodeOutputs.clear();
802}
803
804void AudioContext::addAutomaticPullNode(AudioNode* node)
805{
806    ASSERT(isGraphOwner());
807
808    if (!m_automaticPullNodes.contains(node)) {
809        m_automaticPullNodes.add(node);
810        m_automaticPullNodesNeedUpdating = true;
811    }
812}
813
814void AudioContext::removeAutomaticPullNode(AudioNode* node)
815{
816    ASSERT(isGraphOwner());
817
818    if (m_automaticPullNodes.contains(node)) {
819        m_automaticPullNodes.remove(node);
820        m_automaticPullNodesNeedUpdating = true;
821    }
822}
823
824void AudioContext::updateAutomaticPullNodes()
825{
826    ASSERT(isGraphOwner());
827
828    if (m_automaticPullNodesNeedUpdating) {
829        // Copy from m_automaticPullNodes to m_renderingAutomaticPullNodes.
830        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
831
832        unsigned j = 0;
833        for (HashSet<AudioNode*>::iterator i = m_automaticPullNodes.begin(); i != m_automaticPullNodes.end(); ++i, ++j) {
834            AudioNode* output = *i;
835            m_renderingAutomaticPullNodes[j] = output;
836        }
837
838        m_automaticPullNodesNeedUpdating = false;
839    }
840}
841
842void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
843{
844    ASSERT(isAudioThread());
845
846    for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i)
847        m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess);
848}
849
850const AtomicString& AudioContext::interfaceName() const
851{
852    return EventTargetNames::AudioContext;
853}
854
855ExecutionContext* AudioContext::executionContext() const
856{
857    return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext();
858}
859
860void AudioContext::startRendering()
861{
862    destination()->startRendering();
863}
864
865void AudioContext::fireCompletionEvent()
866{
867    ASSERT(isMainThread());
868    if (!isMainThread())
869        return;
870
871    AudioBuffer* renderedBuffer = m_renderTarget.get();
872
873    ASSERT(renderedBuffer);
874    if (!renderedBuffer)
875        return;
876
877    // Avoid firing the event if the document has already gone away.
878    if (executionContext()) {
879        // Call the offline rendering completion event listener.
880        dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
881    }
882}
883
884void AudioContext::trace(Visitor* visitor)
885{
886    visitor->trace(m_renderTarget);
887    visitor->trace(m_destinationNode);
888    visitor->trace(m_listener);
889    visitor->trace(m_referencedNodes);
890    visitor->trace(m_liveNodes);
891    visitor->trace(m_liveAudioSummingJunctions);
892    EventTargetWithInlineData::trace(visitor);
893}
894
895void AudioContext::addChangedChannelCountMode(AudioNode* node)
896{
897    ASSERT(isGraphOwner());
898    ASSERT(isMainThread());
899    m_deferredCountModeChange.add(node);
900}
901
902void AudioContext::removeChangedChannelCountMode(AudioNode* node)
903{
904    ASSERT(isGraphOwner());
905
906    m_deferredCountModeChange.remove(node);
907}
908
909void AudioContext::updateChangedChannelCountMode()
910{
911    ASSERT(isGraphOwner());
912
913    for (HashSet<AudioNode*>::iterator k = m_deferredCountModeChange.begin(); k != m_deferredCountModeChange.end(); ++k)
914        (*k)->updateChannelCountMode();
915
916    m_deferredCountModeChange.clear();
917}
918
919} // namespace blink
920
921#endif // ENABLE(WEB_AUDIO)
922