e8984673ff7b552e46c19628e7de936cda964569
[WebKit-https.git] / Source / WebCore / Modules / webaudio / AudioContext.cpp
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 "AudioContext.h"
30
31 #include "AsyncAudioDecoder.h"
32 #include "AudioBuffer.h"
33 #include "AudioBufferCallback.h"
34 #include "AudioBufferSourceNode.h"
35 #include "AudioChannelMerger.h"
36 #include "AudioChannelSplitter.h"
37 #include "AudioGainNode.h"
38 #include "AudioListener.h"
39 #include "AudioNodeInput.h"
40 #include "AudioNodeOutput.h"
41 #include "AudioPannerNode.h"
42 #include "BiquadFilterNode.h"
43 #include "ConvolverNode.h"
44 #include "DefaultAudioDestinationNode.h"
45 #include "DelayNode.h"
46 #include "Document.h"
47 #include "DynamicsCompressorNode.h"
48 #include "ExceptionCode.h"
49 #include "FFTFrame.h"
50 #include "HRTFDatabaseLoader.h"
51 #include "HRTFPanner.h"
52 #include "JavaScriptAudioNode.h"
53 #include "OfflineAudioCompletionEvent.h"
54 #include "OfflineAudioDestinationNode.h"
55 #include "Oscillator.h"
56 #include "PlatformString.h"
57 #include "RealtimeAnalyserNode.h"
58 #include "ScriptCallStack.h"
59 #include "WaveShaperNode.h"
60 #include "WaveTable.h"
61
62 #if ENABLE(VIDEO)
63 #include "HTMLMediaElement.h"
64 #include "MediaElementAudioSourceNode.h"
65 #endif
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/MainThread.h>
74 #include <wtf/OwnPtr.h>
75 #include <wtf/PassOwnPtr.h>
76 #include <wtf/RefCounted.h>
77
78 // FIXME: check the proper way to reference an undefined thread ID
79 const int UndefinedThreadIdentifier = 0xffffffff;
80
81 const unsigned MaxNodesToDeletePerQuantum = 10;
82
83 namespace WebCore {
84     
85 namespace {
86     
87 bool isSampleRateRangeGood(float sampleRate)
88 {
89     // FIXME: It would be nice if the minimum sample-rate could be less than 44.1KHz,
90     // but that will require some fixes in HRTFPanner::fftSizeForSampleRate(), and some testing there.
91     return sampleRate >= 44100 && sampleRate <= 96000;
92 }
93
94 }
95
96 // Don't allow more than this number of simultaneous AudioContexts talking to hardware.
97 const unsigned MaxHardwareContexts = 4;
98 unsigned AudioContext::s_hardwareContextCount = 0;
99     
100 PassRefPtr<AudioContext> AudioContext::create(Document* document, ExceptionCode& ec)
101 {
102     UNUSED_PARAM(ec);
103
104     ASSERT(document);
105     ASSERT(isMainThread());
106     if (s_hardwareContextCount >= MaxHardwareContexts)
107         return 0;
108
109     RefPtr<AudioContext> audioContext(adoptRef(new AudioContext(document)));
110     audioContext->suspendIfNeeded();
111     return audioContext.release();
112 }
113
114 PassRefPtr<AudioContext> AudioContext::createOfflineContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode& ec)
115 {
116     ASSERT(document);
117
118     // FIXME: offline contexts have limitations on supported sample-rates.
119     // Currently all AudioContexts must have the same sample-rate.
120     HRTFDatabaseLoader* loader = HRTFDatabaseLoader::loader();
121     if (numberOfChannels > 10 || !isSampleRateRangeGood(sampleRate) || (loader && loader->databaseSampleRate() != sampleRate)) {
122         ec = SYNTAX_ERR;
123         return 0;
124     }
125
126     RefPtr<AudioContext> audioContext(new AudioContext(document, numberOfChannels, numberOfFrames, sampleRate));
127     audioContext->suspendIfNeeded();
128     return audioContext.release();
129 }
130
131 // Constructor for rendering to the audio hardware.
132 AudioContext::AudioContext(Document* document)
133     : ActiveDOMObject(document, this)
134     , m_isInitialized(false)
135     , m_isAudioThreadFinished(false)
136     , m_document(document)
137     , m_destinationNode(0)
138     , m_isDeletionScheduled(false)
139     , m_connectionCount(0)
140     , m_audioThread(0)
141     , m_graphOwnerThread(UndefinedThreadIdentifier)
142     , m_isOfflineContext(false)
143     , m_activeSourceCount(0)
144 {
145     constructCommon();
146
147     m_destinationNode = DefaultAudioDestinationNode::create(this);
148
149     // This sets in motion an asynchronous loading mechanism on another thread.
150     // We can check m_hrtfDatabaseLoader->isLoaded() to find out whether or not it has been fully loaded.
151     // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph
152     // when this has finished (see AudioDestinationNode).
153     m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate());
154 }
155
156 // Constructor for offline (non-realtime) rendering.
157 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
158     : ActiveDOMObject(document, this)
159     , m_isInitialized(false)
160     , m_isAudioThreadFinished(false)
161     , m_document(document)
162     , m_destinationNode(0)
163     , m_connectionCount(0)
164     , m_audioThread(0)
165     , m_graphOwnerThread(UndefinedThreadIdentifier)
166     , m_isOfflineContext(true)
167     , m_activeSourceCount(0)
168 {
169     constructCommon();
170
171     // FIXME: the passed in sampleRate MUST match the hardware sample-rate since HRTFDatabaseLoader is a singleton.
172     m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate);
173
174     // Create a new destination for offline rendering.
175     m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
176     m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());
177 }
178
179 void AudioContext::constructCommon()
180 {
181     FFTFrame::initialize();
182     
183     m_listener = AudioListener::create();
184 }
185
186 AudioContext::~AudioContext()
187 {
188 #if DEBUG_AUDIONODE_REFERENCES
189     printf("%p: AudioContext::~AudioContext()\n", this);
190 #endif
191     // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
192     ASSERT(!m_nodesToDelete.size());
193     ASSERT(!m_referencedNodes.size());
194     ASSERT(!m_finishedNodes.size());
195 }
196
197 void AudioContext::lazyInitialize()
198 {
199     if (!m_isInitialized) {
200         // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
201         ASSERT(!m_isAudioThreadFinished);
202         if (!m_isAudioThreadFinished) {
203             if (m_destinationNode.get()) {
204                 m_destinationNode->initialize();
205
206                 if (!isOfflineContext()) {
207                     // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
208                     // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
209                     // NOTE: for now default AudioContext does not need an explicit startRendering() call from JavaScript.
210                     // We may want to consider requiring it for symmetry with OfflineAudioContext.
211                     m_destinationNode->startRendering();                    
212                     ++s_hardwareContextCount;
213                 }
214
215             }
216             m_isInitialized = true;
217         }
218     }
219 }
220
221 void AudioContext::uninitialize()
222 {
223     ASSERT(isMainThread());
224
225     if (m_isInitialized) {
226         // Protect this object from being deleted before we finish uninitializing.
227         RefPtr<AudioContext> protect(this);
228
229         // This stops the audio thread and all audio rendering.
230         m_destinationNode->uninitialize();
231
232         // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
233         m_isAudioThreadFinished = true;
234
235         // We have to release our reference to the destination node before the context will ever be deleted since the destination node holds a reference to the context.
236         m_destinationNode.clear();
237
238         if (!isOfflineContext()) {
239             ASSERT(s_hardwareContextCount);
240             --s_hardwareContextCount;
241         }
242         
243         // Get rid of the sources which may still be playing.
244         derefUnfinishedSourceNodes();
245
246         deleteMarkedNodes();
247
248         m_isInitialized = false;
249     }
250 }
251
252 bool AudioContext::isInitialized() const
253 {
254     return m_isInitialized;
255 }
256
257 bool AudioContext::isRunnable() const
258 {
259     if (!isInitialized())
260         return false;
261     
262     // Check with the HRTF spatialization system to see if it's finished loading.
263     return m_hrtfDatabaseLoader->isLoaded();
264 }
265
266 void AudioContext::uninitializeDispatch(void* userData)
267 {
268     AudioContext* context = reinterpret_cast<AudioContext*>(userData);
269     ASSERT(context);
270     if (!context)
271         return;
272
273     context->uninitialize();
274 }
275
276 void AudioContext::stop()
277 {
278     m_document = 0; // document is going away
279
280     // Don't call uninitialize() immediately here because the ScriptExecutionContext is in the middle
281     // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
282     // ActiveDOMObjects so let's schedule uninitialize() to be called later.
283     // FIXME: see if there's a more direct way to handle this issue.
284     callOnMainThread(uninitializeDispatch, this);
285 }
286
287 Document* AudioContext::document() const
288 {
289     ASSERT(m_document);
290     return m_document;
291 }
292
293 bool AudioContext::hasDocument()
294 {
295     return m_document;
296 }
297
298 PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode& ec)
299 {
300     RefPtr<AudioBuffer> audioBuffer = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
301     if (!audioBuffer.get()) {
302         ec = SYNTAX_ERR;
303         return 0;
304     }
305
306     return audioBuffer;
307 }
308
309 PassRefPtr<AudioBuffer> AudioContext::createBuffer(ArrayBuffer* arrayBuffer, bool mixToMono, ExceptionCode& ec)
310 {
311     ASSERT(arrayBuffer);
312     if (!arrayBuffer) {
313         ec = SYNTAX_ERR;
314         return 0;
315     }
316
317     RefPtr<AudioBuffer> audioBuffer = AudioBuffer::createFromAudioFileData(arrayBuffer->data(), arrayBuffer->byteLength(), mixToMono, sampleRate());
318     if (!audioBuffer.get()) {
319         ec = SYNTAX_ERR;
320         return 0;
321     }
322
323     return audioBuffer;
324 }
325
326 void AudioContext::decodeAudioData(ArrayBuffer* audioData, PassRefPtr<AudioBufferCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback, ExceptionCode& ec)
327 {
328     if (!audioData) {
329         ec = SYNTAX_ERR;
330         return;
331     }
332     m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback);
333 }
334
335 PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource()
336 {
337     ASSERT(isMainThread());
338     lazyInitialize();
339     RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
340
341     refNode(node.get()); // context keeps reference until source has finished playing
342     return node;
343 }
344
345 #if ENABLE(VIDEO)
346 PassRefPtr<MediaElementAudioSourceNode> AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionCode& ec)
347 {
348     ASSERT(mediaElement);
349     if (!mediaElement) {
350         ec = INVALID_STATE_ERR;
351         return 0;
352     }
353         
354     ASSERT(isMainThread());
355     lazyInitialize();
356     
357     // First check if this media element already has a source node.
358     if (mediaElement->audioSourceNode()) {
359         ec = INVALID_STATE_ERR;
360         return 0;
361     }
362         
363     RefPtr<MediaElementAudioSourceNode> node = MediaElementAudioSourceNode::create(this, mediaElement);
364
365     mediaElement->setAudioSourceNode(node.get());
366
367     refNode(node.get()); // context keeps reference until node is disconnected
368     return node;
369 }
370 #endif
371
372 PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize, ExceptionCode& ec)
373 {
374     // Set number of input/output channels to stereo by default.
375     return createJavaScriptNode(bufferSize, 2, 2, ec);
376 }
377
378 PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize, size_t numberOfInputChannels, ExceptionCode& ec)
379 {
380     // Set number of output channels to stereo by default.
381     return createJavaScriptNode(bufferSize, numberOfInputChannels, 2, ec);
382 }
383
384 PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionCode& ec)
385 {
386     ASSERT(isMainThread());
387     lazyInitialize();
388     RefPtr<JavaScriptAudioNode> node = JavaScriptAudioNode::create(this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
389
390     if (!node.get()) {
391         ec = SYNTAX_ERR;
392         return 0;
393     }
394
395     refNode(node.get()); // context keeps reference until we stop making javascript rendering callbacks
396     return node;
397 }
398
399 PassRefPtr<BiquadFilterNode> AudioContext::createBiquadFilter()
400 {
401     ASSERT(isMainThread());
402     lazyInitialize();
403     return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
404 }
405
406 PassRefPtr<WaveShaperNode> AudioContext::createWaveShaper()
407 {
408     ASSERT(isMainThread());
409     lazyInitialize();
410     return WaveShaperNode::create(this);
411 }
412
413 PassRefPtr<AudioPannerNode> AudioContext::createPanner()
414 {
415     ASSERT(isMainThread());
416     lazyInitialize();
417     return AudioPannerNode::create(this, m_destinationNode->sampleRate());
418 }
419
420 PassRefPtr<ConvolverNode> AudioContext::createConvolver()
421 {
422     ASSERT(isMainThread());
423     lazyInitialize();
424     return ConvolverNode::create(this, m_destinationNode->sampleRate());
425 }
426
427 PassRefPtr<DynamicsCompressorNode> AudioContext::createDynamicsCompressor()
428 {
429     ASSERT(isMainThread());
430     lazyInitialize();
431     return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
432 }
433
434 PassRefPtr<RealtimeAnalyserNode> AudioContext::createAnalyser()
435 {
436     ASSERT(isMainThread());
437     lazyInitialize();
438     return RealtimeAnalyserNode::create(this, m_destinationNode->sampleRate());
439 }
440
441 PassRefPtr<AudioGainNode> AudioContext::createGainNode()
442 {
443     ASSERT(isMainThread());
444     lazyInitialize();
445     return AudioGainNode::create(this, m_destinationNode->sampleRate());
446 }
447
448 PassRefPtr<DelayNode> AudioContext::createDelayNode()
449 {
450     const double defaultMaxDelayTime = 1;
451     return createDelayNode(defaultMaxDelayTime);
452 }
453
454 PassRefPtr<DelayNode> AudioContext::createDelayNode(double maxDelayTime)
455 {
456     ASSERT(isMainThread());
457     lazyInitialize();
458     return DelayNode::create(this, m_destinationNode->sampleRate(), maxDelayTime);
459 }
460
461 PassRefPtr<AudioChannelSplitter> AudioContext::createChannelSplitter()
462 {
463     ASSERT(isMainThread());
464     lazyInitialize();
465     return AudioChannelSplitter::create(this, m_destinationNode->sampleRate());
466 }
467
468 PassRefPtr<AudioChannelMerger> AudioContext::createChannelMerger()
469 {
470     ASSERT(isMainThread());
471     lazyInitialize();
472     return AudioChannelMerger::create(this, m_destinationNode->sampleRate());
473 }
474
475 PassRefPtr<Oscillator> AudioContext::createOscillator()
476 {
477     ASSERT(isMainThread());
478     lazyInitialize();
479     return Oscillator::create(this, m_destinationNode->sampleRate());
480 }
481
482 PassRefPtr<WaveTable> AudioContext::createWaveTable(Float32Array* real, Float32Array* imag, ExceptionCode& ec)
483 {
484     ASSERT(isMainThread());
485     
486     if (!real || !imag || (real->length() != imag->length())) {
487         ec = SYNTAX_ERR;
488         return 0;
489     }
490     
491     lazyInitialize();
492     return WaveTable::create(sampleRate(), real, imag);
493 }
494
495 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
496 {
497     ASSERT(isAudioThread());
498     m_finishedNodes.append(node);
499 }
500
501 void AudioContext::derefFinishedSourceNodes()
502 {
503     ASSERT(isGraphOwner());
504     ASSERT(isAudioThread() || isAudioThreadFinished());
505     for (unsigned i = 0; i < m_finishedNodes.size(); i++)
506         derefNode(m_finishedNodes[i]);
507
508     m_finishedNodes.clear();
509 }
510
511 void AudioContext::refNode(AudioNode* node)
512 {
513     ASSERT(isMainThread());
514     AutoLocker locker(this);
515     
516     node->ref(AudioNode::RefTypeConnection);
517     m_referencedNodes.append(node);
518 }
519
520 void AudioContext::derefNode(AudioNode* node)
521 {
522     ASSERT(isGraphOwner());
523     
524     node->deref(AudioNode::RefTypeConnection);
525
526     for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
527         if (node == m_referencedNodes[i]) {
528             m_referencedNodes.remove(i);
529             break;
530         }
531     }
532 }
533
534 void AudioContext::derefUnfinishedSourceNodes()
535 {
536     ASSERT(isMainThread() && isAudioThreadFinished());
537     for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
538         m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
539
540     m_referencedNodes.clear();
541 }
542
543 void AudioContext::lock(bool& mustReleaseLock)
544 {
545     // Don't allow regular lock in real-time audio thread.
546     ASSERT(isMainThread());
547
548     ThreadIdentifier thisThread = currentThread();
549
550     if (thisThread == m_graphOwnerThread) {
551         // We already have the lock.
552         mustReleaseLock = false;
553     } else {
554         // Acquire the lock.
555         m_contextGraphMutex.lock();
556         m_graphOwnerThread = thisThread;
557         mustReleaseLock = true;
558     }
559 }
560
561 bool AudioContext::tryLock(bool& mustReleaseLock)
562 {
563     ThreadIdentifier thisThread = currentThread();
564     bool isAudioThread = thisThread == audioThread();
565
566     // Try to catch cases of using try lock on main thread - it should use regular lock.
567     ASSERT(isAudioThread || isAudioThreadFinished());
568     
569     if (!isAudioThread) {
570         // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
571         lock(mustReleaseLock);
572         return true;
573     }
574     
575     bool hasLock;
576     
577     if (thisThread == m_graphOwnerThread) {
578         // Thread already has the lock.
579         hasLock = true;
580         mustReleaseLock = false;
581     } else {
582         // Don't already have the lock - try to acquire it.
583         hasLock = m_contextGraphMutex.tryLock();
584         
585         if (hasLock)
586             m_graphOwnerThread = thisThread;
587
588         mustReleaseLock = hasLock;
589     }
590     
591     return hasLock;
592 }
593
594 void AudioContext::unlock()
595 {
596     ASSERT(currentThread() == m_graphOwnerThread);
597
598     m_graphOwnerThread = UndefinedThreadIdentifier;
599     m_contextGraphMutex.unlock();
600 }
601
602 bool AudioContext::isAudioThread() const
603 {
604     return currentThread() == m_audioThread;
605 }
606
607 bool AudioContext::isGraphOwner() const
608 {
609     return currentThread() == m_graphOwnerThread;
610 }
611
612 void AudioContext::addDeferredFinishDeref(AudioNode* node, AudioNode::RefType refType)
613 {
614     ASSERT(isAudioThread());
615     m_deferredFinishDerefList.append(AudioContext::RefInfo(node, refType));
616 }
617
618 void AudioContext::handlePreRenderTasks()
619 {
620     ASSERT(isAudioThread());
621  
622     // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
623     // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
624     bool mustReleaseLock;
625     if (tryLock(mustReleaseLock)) {
626         // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
627         handleDirtyAudioNodeInputs();
628         handleDirtyAudioNodeOutputs();
629         
630         if (mustReleaseLock)
631             unlock();
632     }
633 }
634
635 void AudioContext::handlePostRenderTasks()
636 {
637     ASSERT(isAudioThread());
638  
639     // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
640     // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
641     // from the render graph (in which case they'll render silence).
642     bool mustReleaseLock;
643     if (tryLock(mustReleaseLock)) {
644         // Take care of finishing any derefs where the tryLock() failed previously.
645         handleDeferredFinishDerefs();
646
647         // Dynamically clean up nodes which are no longer needed.
648         derefFinishedSourceNodes();
649
650         // Don't delete in the real-time thread. Let the main thread do it.
651         // Ref-counted objects held by certain AudioNodes may not be thread-safe.
652         scheduleNodeDeletion();
653
654         // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
655         handleDirtyAudioNodeInputs();
656         handleDirtyAudioNodeOutputs();
657         
658         if (mustReleaseLock)
659             unlock();
660     }
661 }
662
663 void AudioContext::handleDeferredFinishDerefs()
664 {
665     ASSERT(isAudioThread() && isGraphOwner());
666     for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
667         AudioNode* node = m_deferredFinishDerefList[i].m_node;
668         AudioNode::RefType refType = m_deferredFinishDerefList[i].m_refType;
669         node->finishDeref(refType);
670     }
671     
672     m_deferredFinishDerefList.clear();
673 }
674
675 void AudioContext::markForDeletion(AudioNode* node)
676 {
677     ASSERT(isGraphOwner());
678     m_nodesToDelete.append(node);
679 }
680
681 void AudioContext::scheduleNodeDeletion()
682 {
683     bool isGood = m_isInitialized && isGraphOwner();
684     ASSERT(isGood);
685     if (!isGood)
686         return;
687
688     // Make sure to call deleteMarkedNodes() on main thread.    
689     if (m_nodesToDelete.size() && !m_isDeletionScheduled) {
690         m_isDeletionScheduled = true;
691
692         // Don't let ourself get deleted before the callback.
693         // See matching deref() in deleteMarkedNodesDispatch().
694         ref();
695         callOnMainThread(deleteMarkedNodesDispatch, this);
696     }
697 }
698
699 void AudioContext::deleteMarkedNodesDispatch(void* userData)
700 {
701     AudioContext* context = reinterpret_cast<AudioContext*>(userData);
702     ASSERT(context);
703     if (!context)
704         return;
705
706     context->deleteMarkedNodes();
707     context->deref();
708 }
709
710 void AudioContext::deleteMarkedNodes()
711 {
712     ASSERT(isMainThread());
713
714     AutoLocker locker(this);
715     
716     // Note: deleting an AudioNode can cause m_nodesToDelete to grow.
717     while (size_t n = m_nodesToDelete.size()) {
718         AudioNode* node = m_nodesToDelete[n - 1];
719         m_nodesToDelete.removeLast();
720
721         // Before deleting the node, clear out any AudioNodeInputs from m_dirtyAudioNodeInputs.
722         unsigned numberOfInputs = node->numberOfInputs();
723         for (unsigned i = 0; i < numberOfInputs; ++i)
724             m_dirtyAudioNodeInputs.remove(node->input(i));
725
726         // Before deleting the node, clear out any AudioNodeOutputs from m_dirtyAudioNodeOutputs.
727         unsigned numberOfOutputs = node->numberOfOutputs();
728         for (unsigned i = 0; i < numberOfOutputs; ++i)
729             m_dirtyAudioNodeOutputs.remove(node->output(i));
730
731         // Finally, delete it.
732         delete node;
733     }
734     
735     m_isDeletionScheduled = false;
736 }
737
738 void AudioContext::markAudioNodeInputDirty(AudioNodeInput* input)
739 {
740     ASSERT(isGraphOwner());    
741     m_dirtyAudioNodeInputs.add(input);
742 }
743
744 void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
745 {
746     ASSERT(isGraphOwner());    
747     m_dirtyAudioNodeOutputs.add(output);
748 }
749
750 void AudioContext::handleDirtyAudioNodeInputs()
751 {
752     ASSERT(isGraphOwner());    
753
754     for (HashSet<AudioNodeInput*>::iterator i = m_dirtyAudioNodeInputs.begin(); i != m_dirtyAudioNodeInputs.end(); ++i)
755         (*i)->updateRenderingState();
756
757     m_dirtyAudioNodeInputs.clear();
758 }
759
760 void AudioContext::handleDirtyAudioNodeOutputs()
761 {
762     ASSERT(isGraphOwner());    
763
764     for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
765         (*i)->updateRenderingState();
766
767     m_dirtyAudioNodeOutputs.clear();
768 }
769
770 const AtomicString& AudioContext::interfaceName() const
771 {
772     return eventNames().interfaceForAudioContext;
773 }
774
775 ScriptExecutionContext* AudioContext::scriptExecutionContext() const
776 {
777     return document();
778 }
779
780 void AudioContext::startRendering()
781 {
782     destination()->startRendering();
783 }
784
785 void AudioContext::fireCompletionEvent()
786 {
787     ASSERT(isMainThread());
788     if (!isMainThread())
789         return;
790         
791     AudioBuffer* renderedBuffer = m_renderTarget.get();
792
793     ASSERT(renderedBuffer);
794     if (!renderedBuffer)
795         return;
796
797     // Avoid firing the event if the document has already gone away.
798     if (hasDocument()) {
799         // Call the offline rendering completion event listener.
800         dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
801     }
802 }
803
804 void AudioContext::incrementActiveSourceCount()
805 {
806     atomicIncrement(&m_activeSourceCount);
807 }
808
809 void AudioContext::decrementActiveSourceCount()
810 {
811     atomicDecrement(&m_activeSourceCount);
812 }
813
814 } // namespace WebCore
815
816 #endif // ENABLE(WEB_AUDIO)