2 * Copyright (C) 2010, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "AudioContext.h"
31 #include "ArrayBuffer.h"
32 #include "AsyncAudioDecoder.h"
33 #include "AudioBuffer.h"
34 #include "AudioBufferCallback.h"
35 #include "AudioBufferSourceNode.h"
36 #include "AudioChannelMerger.h"
37 #include "AudioChannelSplitter.h"
38 #include "AudioGainNode.h"
39 #include "AudioListener.h"
40 #include "AudioNodeInput.h"
41 #include "AudioNodeOutput.h"
42 #include "AudioPannerNode.h"
43 #include "BiquadFilterNode.h"
44 #include "ConvolverNode.h"
45 #include "DefaultAudioDestinationNode.h"
46 #include "DelayNode.h"
48 #include "DynamicsCompressorNode.h"
50 #include "HRTFDatabaseLoader.h"
51 #include "HRTFPanner.h"
52 #include "HighPass2FilterNode.h"
53 #include "JavaScriptAudioNode.h"
54 #include "LowPass2FilterNode.h"
55 #include "OfflineAudioCompletionEvent.h"
56 #include "OfflineAudioDestinationNode.h"
57 #include "PlatformString.h"
58 #include "RealtimeAnalyserNode.h"
59 #include "WaveShaperNode.h"
60 #include "ScriptCallStack.h"
63 #include "HTMLMediaElement.h"
64 #include "MediaElementAudioSourceNode.h"
67 #if DEBUG_AUDIONODE_REFERENCES
71 #include <wtf/MainThread.h>
72 #include <wtf/OwnPtr.h>
73 #include <wtf/PassOwnPtr.h>
74 #include <wtf/RefCounted.h>
76 // FIXME: check the proper way to reference an undefined thread ID
77 const int UndefinedThreadIdentifier = 0xffffffff;
79 const unsigned MaxNodesToDeletePerQuantum = 10;
85 bool isSampleRateRangeGood(double sampleRate)
87 return sampleRate >= 22050 && sampleRate <= 96000;
92 // Don't allow more than this number of simultaneous AudioContexts talking to hardware.
93 const unsigned MaxHardwareContexts = 4;
94 unsigned AudioContext::s_hardwareContextCount = 0;
96 PassRefPtr<AudioContext> AudioContext::create(Document* document)
99 ASSERT(isMainThread());
100 if (s_hardwareContextCount >= MaxHardwareContexts)
103 return adoptRef(new AudioContext(document));
106 PassRefPtr<AudioContext> AudioContext::createOfflineContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate, ExceptionCode& ec)
110 // FIXME: offline contexts have limitations on supported sample-rates.
111 // Currently all AudioContexts must have the same sample-rate.
112 HRTFDatabaseLoader* loader = HRTFDatabaseLoader::loader();
113 if (numberOfChannels > 10 || !isSampleRateRangeGood(sampleRate) || (loader && loader->databaseSampleRate() != sampleRate)) {
118 return adoptRef(new AudioContext(document, numberOfChannels, numberOfFrames, sampleRate));
121 // Constructor for rendering to the audio hardware.
122 AudioContext::AudioContext(Document* document)
123 : ActiveDOMObject(document, this)
124 , m_isInitialized(false)
125 , m_isAudioThreadFinished(false)
126 , m_document(document)
127 , m_destinationNode(0)
128 , m_isDeletionScheduled(false)
129 , m_connectionCount(0)
131 , m_graphOwnerThread(UndefinedThreadIdentifier)
132 , m_isOfflineContext(false)
136 m_destinationNode = DefaultAudioDestinationNode::create(this);
138 // This sets in motion an asynchronous loading mechanism on another thread.
139 // We can check m_hrtfDatabaseLoader->isLoaded() to find out whether or not it has been fully loaded.
140 // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph
141 // when this has finished (see AudioDestinationNode).
142 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate());
145 // Constructor for offline (non-realtime) rendering.
146 AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
147 : ActiveDOMObject(document, this)
148 , m_isInitialized(false)
149 , m_isAudioThreadFinished(false)
150 , m_document(document)
151 , m_destinationNode(0)
152 , m_connectionCount(0)
154 , m_graphOwnerThread(UndefinedThreadIdentifier)
155 , m_isOfflineContext(true)
159 // FIXME: the passed in sampleRate MUST match the hardware sample-rate since HRTFDatabaseLoader is a singleton.
160 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate);
162 // Create a new destination for offline rendering.
163 m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
164 m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());
167 void AudioContext::constructCommon()
169 FFTFrame::initialize();
171 m_listener = AudioListener::create();
172 m_temporaryMonoBus = adoptPtr(new AudioBus(1, AudioNode::ProcessingSizeInFrames));
173 m_temporaryStereoBus = adoptPtr(new AudioBus(2, AudioNode::ProcessingSizeInFrames));
176 AudioContext::~AudioContext()
178 #if DEBUG_AUDIONODE_REFERENCES
179 printf("%p: AudioContext::~AudioContext()\n", this);
181 // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
182 ASSERT(!m_nodesToDelete.size());
183 ASSERT(!m_referencedNodes.size());
184 ASSERT(!m_finishedNodes.size());
187 void AudioContext::lazyInitialize()
189 if (!m_isInitialized) {
190 // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
191 ASSERT(!m_isAudioThreadFinished);
192 if (!m_isAudioThreadFinished) {
193 if (m_destinationNode.get()) {
194 m_destinationNode->initialize();
196 if (!isOfflineContext()) {
197 // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
198 // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
199 // NOTE: for now default AudioContext does not need an explicit startRendering() call from JavaScript.
200 // We may want to consider requiring it for symmetry with OfflineAudioContext.
201 m_destinationNode->startRendering();
202 ++s_hardwareContextCount;
206 m_isInitialized = true;
211 void AudioContext::uninitialize()
213 ASSERT(isMainThread());
215 if (m_isInitialized) {
216 // This stops the audio thread and all audio rendering.
217 m_destinationNode->uninitialize();
219 // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
220 m_isAudioThreadFinished = true;
222 // 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.
223 m_destinationNode.clear();
225 if (!isOfflineContext()) {
226 ASSERT(s_hardwareContextCount);
227 --s_hardwareContextCount;
230 // Get rid of the sources which may still be playing.
231 derefUnfinishedSourceNodes();
235 // Because the AudioBuffers are garbage collected, we can't delete them here.
236 // Instead, at least release the potentially large amount of allocated memory for the audio data.
237 // Note that we do this *after* the context is uninitialized and stops processing audio.
238 for (unsigned i = 0; i < m_allocatedBuffers.size(); ++i)
239 m_allocatedBuffers[i]->releaseMemory();
240 m_allocatedBuffers.clear();
242 m_isInitialized = false;
246 bool AudioContext::isInitialized() const
248 return m_isInitialized;
251 bool AudioContext::isRunnable() const
253 if (!isInitialized())
256 // Check with the HRTF spatialization system to see if it's finished loading.
257 return m_hrtfDatabaseLoader->isLoaded();
260 void AudioContext::uninitializeDispatch(void* userData)
262 AudioContext* context = reinterpret_cast<AudioContext*>(userData);
267 context->uninitialize();
270 void AudioContext::stop()
272 m_document = 0; // document is going away
274 // Don't call uninitialize() immediately here because the ScriptExecutionContext is in the middle
275 // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
276 // ActiveDOMObjects so let's schedule uninitialize() to be called later.
277 // FIXME: see if there's a more direct way to handle this issue.
278 callOnMainThread(uninitializeDispatch, this);
281 Document* AudioContext::document() const
287 bool AudioContext::hasDocument()
292 void AudioContext::refBuffer(PassRefPtr<AudioBuffer> buffer)
294 m_allocatedBuffers.append(buffer);
297 PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, double sampleRate)
299 if (!isSampleRateRangeGood(sampleRate) || numberOfChannels > 10 || !numberOfFrames)
302 return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
305 PassRefPtr<AudioBuffer> AudioContext::createBuffer(ArrayBuffer* arrayBuffer, bool mixToMono)
311 return AudioBuffer::createFromAudioFileData(arrayBuffer->data(), arrayBuffer->byteLength(), mixToMono, sampleRate());
314 void AudioContext::decodeAudioData(ArrayBuffer* audioData, PassRefPtr<AudioBufferCallback> successCallback, PassRefPtr<AudioBufferCallback> errorCallback, ExceptionCode& ec)
320 m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback);
323 PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource()
325 ASSERT(isMainThread());
327 RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
329 refNode(node.get()); // context keeps reference until source has finished playing
334 PassRefPtr<MediaElementAudioSourceNode> AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionCode& ec)
336 ASSERT(mediaElement);
338 ec = INVALID_STATE_ERR;
342 ASSERT(isMainThread());
345 // First check if this media element already has a source node.
346 if (mediaElement->audioSourceNode()) {
347 ec = INVALID_STATE_ERR;
351 RefPtr<MediaElementAudioSourceNode> node = MediaElementAudioSourceNode::create(this, mediaElement);
353 mediaElement->setAudioSourceNode(node.get());
355 refNode(node.get()); // context keeps reference until node is disconnected
360 PassRefPtr<JavaScriptAudioNode> AudioContext::createJavaScriptNode(size_t bufferSize)
362 ASSERT(isMainThread());
364 RefPtr<JavaScriptAudioNode> node = JavaScriptAudioNode::create(this, m_destinationNode->sampleRate(), bufferSize);
366 refNode(node.get()); // context keeps reference until we stop making javascript rendering callbacks
370 PassRefPtr<BiquadFilterNode> AudioContext::createBiquadFilter()
372 ASSERT(isMainThread());
374 return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
377 PassRefPtr<WaveShaperNode> AudioContext::createWaveShaper()
379 ASSERT(isMainThread());
381 return WaveShaperNode::create(this);
384 PassRefPtr<LowPass2FilterNode> AudioContext::createLowPass2Filter()
386 ASSERT(isMainThread());
389 document()->addMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "createLowPass2Filter() is deprecated. Use createBiquadFilter() instead.", 1, String(), 0);
391 return LowPass2FilterNode::create(this, m_destinationNode->sampleRate());
394 PassRefPtr<HighPass2FilterNode> AudioContext::createHighPass2Filter()
396 ASSERT(isMainThread());
399 document()->addMessage(JSMessageSource, LogMessageType, WarningMessageLevel, "createHighPass2Filter() is deprecated. Use createBiquadFilter() instead.", 1, String(), 0);
401 return HighPass2FilterNode::create(this, m_destinationNode->sampleRate());
404 PassRefPtr<AudioPannerNode> AudioContext::createPanner()
406 ASSERT(isMainThread());
408 return AudioPannerNode::create(this, m_destinationNode->sampleRate());
411 PassRefPtr<ConvolverNode> AudioContext::createConvolver()
413 ASSERT(isMainThread());
415 return ConvolverNode::create(this, m_destinationNode->sampleRate());
418 PassRefPtr<DynamicsCompressorNode> AudioContext::createDynamicsCompressor()
420 ASSERT(isMainThread());
422 return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
425 PassRefPtr<RealtimeAnalyserNode> AudioContext::createAnalyser()
427 ASSERT(isMainThread());
429 return RealtimeAnalyserNode::create(this, m_destinationNode->sampleRate());
432 PassRefPtr<AudioGainNode> AudioContext::createGainNode()
434 ASSERT(isMainThread());
436 return AudioGainNode::create(this, m_destinationNode->sampleRate());
439 PassRefPtr<DelayNode> AudioContext::createDelayNode()
441 ASSERT(isMainThread());
443 return DelayNode::create(this, m_destinationNode->sampleRate());
446 PassRefPtr<AudioChannelSplitter> AudioContext::createChannelSplitter()
448 ASSERT(isMainThread());
450 return AudioChannelSplitter::create(this, m_destinationNode->sampleRate());
453 PassRefPtr<AudioChannelMerger> AudioContext::createChannelMerger()
455 ASSERT(isMainThread());
457 return AudioChannelMerger::create(this, m_destinationNode->sampleRate());
460 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
462 ASSERT(isAudioThread());
463 m_finishedNodes.append(node);
466 void AudioContext::derefFinishedSourceNodes()
468 ASSERT(isGraphOwner());
469 ASSERT(isAudioThread() || isAudioThreadFinished());
470 for (unsigned i = 0; i < m_finishedNodes.size(); i++)
471 derefNode(m_finishedNodes[i]);
473 m_finishedNodes.clear();
476 void AudioContext::refNode(AudioNode* node)
478 ASSERT(isMainThread());
479 AutoLocker locker(this);
481 node->ref(AudioNode::RefTypeConnection);
482 m_referencedNodes.append(node);
485 void AudioContext::derefNode(AudioNode* node)
487 ASSERT(isGraphOwner());
489 node->deref(AudioNode::RefTypeConnection);
491 for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
492 if (node == m_referencedNodes[i]) {
493 m_referencedNodes.remove(i);
499 void AudioContext::derefUnfinishedSourceNodes()
501 ASSERT(isMainThread() && isAudioThreadFinished());
502 for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
503 m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
505 m_referencedNodes.clear();
508 void AudioContext::lock(bool& mustReleaseLock)
510 // Don't allow regular lock in real-time audio thread.
511 ASSERT(isMainThread());
513 ThreadIdentifier thisThread = currentThread();
515 if (thisThread == m_graphOwnerThread) {
516 // We already have the lock.
517 mustReleaseLock = false;
520 m_contextGraphMutex.lock();
521 m_graphOwnerThread = thisThread;
522 mustReleaseLock = true;
526 bool AudioContext::tryLock(bool& mustReleaseLock)
528 ThreadIdentifier thisThread = currentThread();
529 bool isAudioThread = thisThread == audioThread();
531 // Try to catch cases of using try lock on main thread - it should use regular lock.
532 ASSERT(isAudioThread || isAudioThreadFinished());
534 if (!isAudioThread) {
535 // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
536 lock(mustReleaseLock);
542 if (thisThread == m_graphOwnerThread) {
543 // Thread already has the lock.
545 mustReleaseLock = false;
547 // Don't already have the lock - try to acquire it.
548 hasLock = m_contextGraphMutex.tryLock();
551 m_graphOwnerThread = thisThread;
553 mustReleaseLock = hasLock;
559 void AudioContext::unlock()
561 ASSERT(currentThread() == m_graphOwnerThread);
563 m_graphOwnerThread = UndefinedThreadIdentifier;
564 m_contextGraphMutex.unlock();
567 bool AudioContext::isAudioThread() const
569 return currentThread() == m_audioThread;
572 bool AudioContext::isGraphOwner() const
574 return currentThread() == m_graphOwnerThread;
577 void AudioContext::addDeferredFinishDeref(AudioNode* node, AudioNode::RefType refType)
579 ASSERT(isAudioThread());
580 m_deferredFinishDerefList.append(AudioContext::RefInfo(node, refType));
583 void AudioContext::handlePreRenderTasks()
585 ASSERT(isAudioThread());
587 // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
588 // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
589 bool mustReleaseLock;
590 if (tryLock(mustReleaseLock)) {
591 // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
592 handleDirtyAudioNodeInputs();
593 handleDirtyAudioNodeOutputs();
600 void AudioContext::handlePostRenderTasks()
602 ASSERT(isAudioThread());
604 // Must use a tryLock() here too. Don't worry, the lock will very rarely be contended and this method is called frequently.
605 // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
606 // from the render graph (in which case they'll render silence).
607 bool mustReleaseLock;
608 if (tryLock(mustReleaseLock)) {
609 // Take care of finishing any derefs where the tryLock() failed previously.
610 handleDeferredFinishDerefs();
612 // Dynamically clean up nodes which are no longer needed.
613 derefFinishedSourceNodes();
615 // Don't delete in the real-time thread. Let the main thread do it.
616 // Ref-counted objects held by certain AudioNodes may not be thread-safe.
617 scheduleNodeDeletion();
619 // Fixup the state of any dirty AudioNodeInputs and AudioNodeOutputs.
620 handleDirtyAudioNodeInputs();
621 handleDirtyAudioNodeOutputs();
628 void AudioContext::handleDeferredFinishDerefs()
630 ASSERT(isAudioThread() && isGraphOwner());
631 for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
632 AudioNode* node = m_deferredFinishDerefList[i].m_node;
633 AudioNode::RefType refType = m_deferredFinishDerefList[i].m_refType;
634 node->finishDeref(refType);
637 m_deferredFinishDerefList.clear();
640 void AudioContext::markForDeletion(AudioNode* node)
642 ASSERT(isGraphOwner());
643 m_nodesToDelete.append(node);
646 void AudioContext::scheduleNodeDeletion()
648 bool isGood = m_isInitialized && isGraphOwner();
653 // Make sure to call deleteMarkedNodes() on main thread.
654 if (m_nodesToDelete.size() && !m_isDeletionScheduled) {
655 m_isDeletionScheduled = true;
657 // Don't let ourself get deleted before the callback.
658 // See matching deref() in deleteMarkedNodesDispatch().
660 callOnMainThread(deleteMarkedNodesDispatch, this);
664 void AudioContext::deleteMarkedNodesDispatch(void* userData)
666 AudioContext* context = reinterpret_cast<AudioContext*>(userData);
671 context->deleteMarkedNodes();
675 void AudioContext::deleteMarkedNodes()
677 ASSERT(isMainThread());
679 AutoLocker locker(this);
681 // Note: deleting an AudioNode can cause m_nodesToDelete to grow.
682 while (size_t n = m_nodesToDelete.size()) {
683 AudioNode* node = m_nodesToDelete[n - 1];
684 m_nodesToDelete.removeLast();
686 // Before deleting the node, clear out any AudioNodeInputs from m_dirtyAudioNodeInputs.
687 unsigned numberOfInputs = node->numberOfInputs();
688 for (unsigned i = 0; i < numberOfInputs; ++i)
689 m_dirtyAudioNodeInputs.remove(node->input(i));
691 // Before deleting the node, clear out any AudioNodeOutputs from m_dirtyAudioNodeOutputs.
692 unsigned numberOfOutputs = node->numberOfOutputs();
693 for (unsigned i = 0; i < numberOfOutputs; ++i)
694 m_dirtyAudioNodeOutputs.remove(node->output(i));
696 // Finally, delete it.
700 m_isDeletionScheduled = false;
703 void AudioContext::markAudioNodeInputDirty(AudioNodeInput* input)
705 ASSERT(isGraphOwner());
706 m_dirtyAudioNodeInputs.add(input);
709 void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
711 ASSERT(isGraphOwner());
712 m_dirtyAudioNodeOutputs.add(output);
715 void AudioContext::handleDirtyAudioNodeInputs()
717 ASSERT(isGraphOwner());
719 for (HashSet<AudioNodeInput*>::iterator i = m_dirtyAudioNodeInputs.begin(); i != m_dirtyAudioNodeInputs.end(); ++i)
720 (*i)->updateRenderingState();
722 m_dirtyAudioNodeInputs.clear();
725 void AudioContext::handleDirtyAudioNodeOutputs()
727 ASSERT(isGraphOwner());
729 for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
730 (*i)->updateRenderingState();
732 m_dirtyAudioNodeOutputs.clear();
735 ScriptExecutionContext* AudioContext::scriptExecutionContext() const
740 AudioContext* AudioContext::toAudioContext()
745 void AudioContext::startRendering()
747 destination()->startRendering();
750 void AudioContext::fireCompletionEvent()
752 ASSERT(isMainThread());
756 AudioBuffer* renderedBuffer = m_renderTarget.get();
758 ASSERT(renderedBuffer);
762 // Avoid firing the event if the document has already gone away.
764 // Call the offline rendering completion event listener.
765 dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
769 } // namespace WebCore
771 #endif // ENABLE(WEB_AUDIO)