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