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