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