Home | History | Annotate | Download | only in webaudio
      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)
    612