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