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