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