2011-06-08 Chris Rogers <crogers@google.com>
[WebKit-https.git] / Source / WebCore / 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 "ArrayBuffer.h"
32 #include "AudioBuffer.h"
33 #include "AudioBufferSourceNode.h"
34 #include "AudioChannelMerger.h"
35 #include "AudioChannelSplitter.h"
36 #include "AudioGainNode.h"
37 #include "AudioListener.h"
38 #include "AudioNodeInput.h"
39 #include "AudioNodeOutput.h"
40 #include "AudioPannerNode.h"
41 #include "BiquadFilterNode.h"
42 #include "ConvolverNode.h"
43 #include "DefaultAudioDestinationNode.h"
44 #include "DelayNode.h"
45 #include "Document.h"
46 #include "DynamicsCompressorNode.h"
47 #include "FFTFrame.h"
48 #include "HRTFDatabaseLoader.h"
49 #include "HRTFPanner.h"
50 #include "HighPass2FilterNode.h"
51 #include "JavaScriptAudioNode.h"
52 #include "LowPass2FilterNode.h"
53 #include "OfflineAudioCompletionEvent.h"
54 #include "OfflineAudioDestinationNode.h"
55 #include "PlatformString.h"
56 #include "RealtimeAnalyserNode.h"
57 #include "ScriptCallStack.h"
58
59 #if DEBUG_AUDIONODE_REFERENCES
60 #include <stdio.h>
61 #endif
62
63 #include <wtf/OwnPtr.h>
64 #include <wtf/PassOwnPtr.h>
65 #include <wtf/RefCounted.h>
66
67 // FIXME: check the proper way to reference an undefined thread ID
68 const int UndefinedThreadIdentifier = 0xffffffff;
69
70 const unsigned MaxNodesToDeletePerQuantum = 10;
71
72 namespace WebCore {
73
74 PassRefPtr<AudioContext> AudioContext::create(Document* document)
75 {
76     return adoptRef(new AudioContext(document));
77 }
78
79 PassRefPtr<AudioContext> AudioContext::createOfflineContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
80 {
81     return adoptRef(new AudioContext(document, numberOfChannels, numberOfFrames, sampleRate));
82 }
83
84 // Constructor for rendering to the audio hardware.
85 AudioContext::AudioContext(Document* document)
86     : ActiveDOMObject(document, this)
87     , m_isInitialized(false)
88     , m_isAudioThreadFinished(false)
89     , m_document(document)
90     , m_destinationNode(0)
91     , m_connectionCount(0)
92     , m_audioThread(0)
93     , m_graphOwnerThread(UndefinedThreadIdentifier)
94     , m_isOfflineContext(false)
95 {
96     constructCommon();
97
98     m_destinationNode = DefaultAudioDestinationNode::create(this);
99
100     // This sets in motion an asynchronous loading mechanism on another thread.
101     // We can check m_hrtfDatabaseLoader->isLoaded() to find out whether or not it has been fully loaded.
102     // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph
103     // when this has finished (see AudioDestinationNode).
104     m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate());
105
106     // FIXME: for now default AudioContext does not need an explicit startRendering() call.
107     // We may want to consider requiring it for symmetry with OfflineAudioContext
108     m_destinationNode->startRendering();
109 }
110
111 // Constructor for offline (non-realtime) rendering.
112 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
113     : ActiveDOMObject(document, this)
114     , m_isInitialized(false)
115     , m_isAudioThreadFinished(false)
116     , m_document(document)
117     , m_destinationNode(0)
118     , m_connectionCount(0)
119     , m_audioThread(0)
120     , m_graphOwnerThread(UndefinedThreadIdentifier)
121     , m_isOfflineContext(true)
122 {
123     constructCommon();
124
125     // FIXME: the passed in sampleRate MUST match the hardware sample-rate since HRTFDatabaseLoader is a singleton.
126     m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate);
127
128     // Create a new destination for offline rendering.
129     m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
130     m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());
131 }
132
133 void AudioContext::constructCommon()
134 {
135     // Note: because adoptRef() won't be called until we leave this constructor, but code in this constructor needs to reference this context,
136     // relax the check.
137     relaxAdoptionRequirement();
138     
139     FFTFrame::initialize();
140     
141     m_listener = AudioListener::create();
142     m_temporaryMonoBus = adoptPtr(new AudioBus(1, AudioNode::ProcessingSizeInFrames));
143     m_temporaryStereoBus = adoptPtr(new AudioBus(2, AudioNode::ProcessingSizeInFrames));
144 }
145
146 AudioContext::~AudioContext()
147 {
148 #if DEBUG_AUDIONODE_REFERENCES
149     printf("%p: AudioContext::~AudioContext()\n", this);
150 #endif    
151     // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
152     ASSERT(!m_nodesToDelete.size());
153     ASSERT(!m_referencedNodes.size());
154     ASSERT(!m_finishedNodes.size());
155 }
156
157 void AudioContext::lazyInitialize()
158 {
159     if (!m_isInitialized) {
160         // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
161         ASSERT(!m_isAudioThreadFinished);
162         if (!m_isAudioThreadFinished) {
163             if (m_destinationNode.get()) {
164                 // This starts the audio thread.  The destination node's provideInput() method will now be called repeatedly to render audio.
165                 // Each time provideInput() is called, a portion of the audio stream is rendered.  Let's call this time period a "render quantum".
166                 m_destinationNode->initialize();
167             }
168             m_isInitialized = true;
169         }
170     }
171 }
172
173 void AudioContext::uninitialize()
174 {
175     if (m_isInitialized) {    
176         // This stops the audio thread and all audio rendering.
177         m_destinationNode->uninitialize();
178
179         // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
180         m_isAudioThreadFinished = true;
181
182         // 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.
183         m_destinationNode.clear();
184         
185         // Get rid of the sources which may still be playing.
186         derefUnfinishedSourceNodes();
187         
188         // Because the AudioBuffers are garbage collected, we can't delete them here.
189         // Instead, at least release the potentially large amount of allocated memory for the audio data.
190         // Note that we do this *after* the context is uninitialized and stops processing audio.
191         for (unsigned i = 0; i < m_allocatedBuffers.size(); ++i)
192             m_allocatedBuffers[i]->releaseMemory();
193         m_allocatedBuffers.clear();
194     
195         m_isInitialized = false;
196     }
197 }
198
199 bool AudioContext::isInitialized() const
200 {
201     return m_isInitialized;
202 }
203
204 bool AudioContext::isRunnable() const
205 {
206     if (!isInitialized())
207         return false;
208     
209     // Check with the HRTF spatialization system to see if it's finished loading.
210     return m_hrtfDatabaseLoader->isLoaded();
211 }
212
213 void AudioContext::stop()
214 {
215     m_document = 0; // document is going away
216     uninitialize();
217 }
218
219 Document* AudioContext::document() const
220 {
221     ASSERT(m_document);
222     return m_document;
223 }
224
225 bool AudioContext::hasDocument()
226 {
227     return m_document;
228 }
229
230 void AudioContext::refBuffer(PassRefPtr<AudioBuffer> buffer)
231 {
232     m_allocatedBuffers.append(buffer);
233 }
234
235 PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
236 {
237     return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
238 }
239
240 PassRefPtr<AudioBuffer> AudioContext::createBuffer(ArrayBuffer* arrayBuffer, bool mixToMono)
241 {
242     ASSERT(arrayBuffer);
243     if (!arrayBuffer)
244         return 0;
245     
246     return AudioBuffer::createFromAudioFileData(arrayBuffer->data(), arrayBuffer->byteLength(), mixToMono, sampleRate());
247 }
248
249 PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource()
250 {
251     ASSERT(isMainThread());
252     lazyInitialize();
253     RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
254
255     refNode(node.get()); // context keeps reference until source has finished playing
256     return node;
257 }
258
259 PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize)
260 {
261     ASSERT(isMainThread());
262     lazyInitialize();
263     RefPtr<JavaScriptAudioNode> node = JavaScriptAudioNode::create(this, m_destinationNode->sampleRate(), bufferSize);
264
265     refNode(node.get()); // context keeps reference until we stop making javascript rendering callbacks
266     return node;
267 }
268
269 PassRefPtr<BiquadFilterNode> AudioContext::createBiquadFilter()
270 {
271     ASSERT(isMainThread());
272     lazyInitialize();
273     return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
274 }
275
276 PassRefPtr<LowPass2FilterNode> AudioContext::createLowPass2Filter()
277 {
278     ASSERT(isMainThread());
279     lazyInitialize();
280     if (document())
281         document()->addMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "createLowPass2Filter() is deprecated.  Use createBiquadFilter() instead.", 1, String(), 0);
282         
283     return LowPass2FilterNode::create(this, m_destinationNode->sampleRate());
284 }
285
286 PassRefPtr<HighPass2FilterNode> AudioContext::createHighPass2Filter()
287 {
288     ASSERT(isMainThread());
289     lazyInitialize();
290     if (document())
291         document()->addMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "createHighPass2Filter() is deprecated.  Use createBiquadFilter() instead.", 1, String(), 0);
292
293     return HighPass2FilterNode::create(this, m_destinationNode->sampleRate());
294 }
295
296 PassRefPtr<AudioPannerNode> AudioContext::createPanner()
297 {
298     ASSERT(isMainThread());
299     lazyInitialize();
300     return AudioPannerNode::create(this, m_destinationNode->sampleRate());
301 }
302
303 PassRefPtr<ConvolverNode> AudioContext::createConvolver()
304 {
305     ASSERT(isMainThread());
306     lazyInitialize();
307     return ConvolverNode::create(this, m_destinationNode->sampleRate());
308 }
309
310 PassRefPtr<DynamicsCompressorNode> AudioContext::createDynamicsCompressor()
311 {
312     ASSERT(isMainThread());
313     lazyInitialize();
314     return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
315 }
316
317 PassRefPtr<RealtimeAnalyserNode> AudioContext::createAnalyser()
318 {
319     ASSERT(isMainThread());
320     lazyInitialize();
321     return RealtimeAnalyserNode::create(this, m_destinationNode->sampleRate());
322 }
323
324 PassRefPtr<AudioGainNode> AudioContext::createGainNode()
325 {
326     ASSERT(isMainThread());
327     lazyInitialize();
328     return AudioGainNode::create(this, m_destinationNode->sampleRate());
329 }
330
331 PassRefPtr<DelayNode> AudioContext::createDelayNode()
332 {
333     ASSERT(isMainThread());
334     lazyInitialize();
335     return DelayNode::create(this, m_destinationNode->sampleRate());
336 }
337
338 PassRefPtr<AudioChannelSplitter> AudioContext::createChannelSplitter()
339 {
340     ASSERT(isMainThread());
341     lazyInitialize();
342     return AudioChannelSplitter::create(this, m_destinationNode->sampleRate());
343 }
344
345 PassRefPtr<AudioChannelMerger> AudioContext::createChannelMerger()
346 {
347     ASSERT(isMainThread());
348     lazyInitialize();
349     return AudioChannelMerger::create(this, m_destinationNode->sampleRate());
350 }
351
352 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
353 {
354     ASSERT(isAudioThread());
355     m_finishedNodes.append(node);
356 }
357
358 void AudioContext::derefFinishedSourceNodes()
359 {
360     ASSERT(isGraphOwner());
361     ASSERT(isAudioThread() || isAudioThreadFinished());
362     for (unsigned i = 0; i < m_finishedNodes.size(); i++)
363         derefNode(m_finishedNodes[i]);
364
365     m_finishedNodes.clear();
366 }
367
368 void AudioContext::refNode(AudioNode* node)
369 {
370     ASSERT(isMainThread());
371     AutoLocker locker(this);
372     
373     node->ref(AudioNode::RefTypeConnection);
374     m_referencedNodes.append(node);
375 }
376
377 void AudioContext::derefNode(AudioNode* node)
378 {
379     ASSERT(isGraphOwner());
380     
381     node->deref(AudioNode::RefTypeConnection);
382
383     for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
384         if (node == m_referencedNodes[i]) {
385             m_referencedNodes.remove(i);
386             break;
387         }
388     }
389 }
390
391 void AudioContext::derefUnfinishedSourceNodes()
392 {
393     ASSERT(isMainThread() && isAudioThreadFinished());
394     for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
395         m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
396
397     m_referencedNodes.clear();
398 }
399
400 void AudioContext::lock(bool& mustReleaseLock)
401 {
402     // Don't allow regular lock in real-time audio thread.
403     ASSERT(isMainThread());
404
405     ThreadIdentifier thisThread = currentThread();
406
407     if (thisThread == m_graphOwnerThread) {
408         // We already have the lock.
409         mustReleaseLock = false;
410     } else {
411         // Acquire the lock.
412         m_contextGraphMutex.lock();
413         m_graphOwnerThread = thisThread;
414         mustReleaseLock = true;
415     }
416 }
417
418 bool AudioContext::tryLock(bool& mustReleaseLock)
419 {
420     ThreadIdentifier thisThread = currentThread();
421     bool isAudioThread = thisThread == audioThread();
422
423     // Try to catch cases of using try lock on main thread - it should use regular lock.
424     ASSERT(isAudioThread || isAudioThreadFinished());
425     
426     if (!isAudioThread) {
427         // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
428         lock(mustReleaseLock);
429         return true;
430     }
431     
432     bool hasLock;
433     
434     if (thisThread == m_graphOwnerThread) {
435         // Thread already has the lock.
436         hasLock = true;
437         mustReleaseLock = false;
438     } else {
439         // Don't already have the lock - try to acquire it.
440         hasLock = m_contextGraphMutex.tryLock();
441         
442         if (hasLock)
443             m_graphOwnerThread = thisThread;
444
445         mustReleaseLock = hasLock;
446     }
447     
448     return hasLock;
449 }
450
451 void AudioContext::unlock()
452 {
453     ASSERT(currentThread() == m_graphOwnerThread);
454
455     m_graphOwnerThread = UndefinedThreadIdentifier;
456     m_contextGraphMutex.unlock();
457 }
458
459 bool AudioContext::isAudioThread() const
460 {
461     return currentThread() == m_audioThread;
462 }
463
464 bool AudioContext::isGraphOwner() const
465 {
466     return currentThread() == m_graphOwnerThread;
467 }
468
469 void AudioContext::addDeferredFinishDeref(AudioNode* node, AudioNode::RefType refType)
470 {
471     ASSERT(isAudioThread());
472     m_deferredFinishDerefList.append(AudioContext::RefInfo(node, refType));
473 }
474
475 void AudioContext::handlePreRenderTasks()
476 {
477     ASSERT(isAudioThread());
478  
479     // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
480     // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
481     bool mustReleaseLock;
482     if (tryLock(mustReleaseLock)) {
483         // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
484         handleDirtyAudioNodeInputs();
485         handleDirtyAudioNodeOutputs();
486         
487         if (mustReleaseLock)
488             unlock();
489     }
490 }
491
492 void AudioContext::handlePostRenderTasks()
493 {
494     ASSERT(isAudioThread());
495  
496     // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
497     // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
498     // from the render graph (in which case they'll render silence).
499     bool mustReleaseLock;
500     if (tryLock(mustReleaseLock)) {
501         // Take care of finishing any derefs where the tryLock() failed previously.
502         handleDeferredFinishDerefs();
503
504         // Dynamically clean up nodes which are no longer needed.
505         derefFinishedSourceNodes();
506
507         // Finally actually delete.
508         deleteMarkedNodes();
509
510         // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
511         handleDirtyAudioNodeInputs();
512         handleDirtyAudioNodeOutputs();
513         
514         if (mustReleaseLock)
515             unlock();
516     }
517 }
518
519 void AudioContext::handleDeferredFinishDerefs()
520 {
521     ASSERT(isAudioThread() && isGraphOwner());
522     for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
523         AudioNode* node = m_deferredFinishDerefList[i].m_node;
524         AudioNode::RefType refType = m_deferredFinishDerefList[i].m_refType;
525         node->finishDeref(refType);
526     }
527     
528     m_deferredFinishDerefList.clear();
529 }
530
531 void AudioContext::markForDeletion(AudioNode* node)
532 {
533     ASSERT(isGraphOwner());
534     m_nodesToDelete.append(node);
535 }
536
537 void AudioContext::deleteMarkedNodes()
538 {
539     ASSERT(isGraphOwner() || isAudioThreadFinished());
540
541     // Note: deleting an AudioNode can cause m_nodesToDelete to grow.
542     size_t nodesDeleted = 0;
543     while (size_t n = m_nodesToDelete.size()) {
544         AudioNode* node = m_nodesToDelete[n - 1];
545         m_nodesToDelete.removeLast();
546
547         // Before deleting the node, clear out any AudioNodeInputs from m_dirtyAudioNodeInputs.
548         unsigned numberOfInputs = node->numberOfInputs();
549         for (unsigned i = 0; i < numberOfInputs; ++i)
550             m_dirtyAudioNodeInputs.remove(node->input(i));
551
552         // Before deleting the node, clear out any AudioNodeOutputs from m_dirtyAudioNodeOutputs.
553         unsigned numberOfOutputs = node->numberOfOutputs();
554         for (unsigned i = 0; i < numberOfOutputs; ++i)
555             m_dirtyAudioNodeOutputs.remove(node->output(i));
556
557         // Finally, delete it.
558         delete node;
559
560         // Don't delete too many nodes per render quantum since we don't want to do too much work in the realtime audio thread.
561         if (++nodesDeleted > MaxNodesToDeletePerQuantum)
562             break;
563     }
564 }
565
566 void AudioContext::markAudioNodeInputDirty(AudioNodeInput* input)
567 {
568     ASSERT(isGraphOwner());    
569     m_dirtyAudioNodeInputs.add(input);
570 }
571
572 void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
573 {
574     ASSERT(isGraphOwner());    
575     m_dirtyAudioNodeOutputs.add(output);
576 }
577
578 void AudioContext::handleDirtyAudioNodeInputs()
579 {
580     ASSERT(isGraphOwner());    
581
582     for (HashSet<AudioNodeInput*>::iterator i = m_dirtyAudioNodeInputs.begin(); i != m_dirtyAudioNodeInputs.end(); ++i)
583         (*i)->updateRenderingState();
584
585     m_dirtyAudioNodeInputs.clear();
586 }
587
588 void AudioContext::handleDirtyAudioNodeOutputs()
589 {
590     ASSERT(isGraphOwner());    
591
592     for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
593         (*i)->updateRenderingState();
594
595     m_dirtyAudioNodeOutputs.clear();
596 }
597
598 ScriptExecutionContext* AudioContext::scriptExecutionContext() const
599 {
600     return document();
601 }
602
603 AudioContext* AudioContext::toAudioContext()
604 {
605     return this;
606 }
607
608 void AudioContext::startRendering()
609 {
610     destination()->startRendering();
611 }
612
613 void AudioContext::fireCompletionEvent()
614 {
615     ASSERT(isMainThread());
616     if (!isMainThread())
617         return;
618         
619     AudioBuffer* renderedBuffer = m_renderTarget.get();
620
621     ASSERT(renderedBuffer);
622     if (!renderedBuffer)
623         return;
624
625     // Avoid firing the event if the document has already gone away.
626     if (hasDocument()) {
627         // Call the offline rendering completion event listener.
628         dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
629     }
630 }
631
632 } // namespace WebCore
633
634 #endif // ENABLE(WEB_AUDIO)