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