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