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 "modules/webaudio/AudioNode.h"
     30 
     31 #include "bindings/v8/ExceptionState.h"
     32 #include "core/dom/ExceptionCode.h"
     33 #include "modules/webaudio/AudioContext.h"
     34 #include "modules/webaudio/AudioNodeInput.h"
     35 #include "modules/webaudio/AudioNodeOutput.h"
     36 #include "modules/webaudio/AudioParam.h"
     37 #include "wtf/Atomics.h"
     38 #include "wtf/MainThread.h"
     39 
     40 #if DEBUG_AUDIONODE_REFERENCES
     41 #include <stdio.h>
     42 #endif
     43 
     44 namespace WebCore {
     45 
     46 AudioNode::AudioNode(AudioContext* context, float sampleRate)
     47     : m_isInitialized(false)
     48     , m_nodeType(NodeTypeUnknown)
     49     , m_context(context)
     50     , m_sampleRate(sampleRate)
     51     , m_lastProcessingTime(-1)
     52     , m_lastNonSilentTime(-1)
     53     , m_normalRefCount(1) // start out with normal refCount == 1 (like WTF::RefCounted class)
     54     , m_connectionRefCount(0)
     55     , m_isMarkedForDeletion(false)
     56     , m_isDisabled(false)
     57     , m_channelCount(2)
     58     , m_channelCountMode(Max)
     59     , m_channelInterpretation(AudioBus::Speakers)
     60 {
     61     ScriptWrappable::init(this);
     62 #if DEBUG_AUDIONODE_REFERENCES
     63     if (!s_isNodeCountInitialized) {
     64         s_isNodeCountInitialized = true;
     65         atexit(AudioNode::printNodeCounts);
     66     }
     67 #endif
     68 }
     69 
     70 AudioNode::~AudioNode()
     71 {
     72 #if DEBUG_AUDIONODE_REFERENCES
     73     --s_nodeCount[nodeType()];
     74     fprintf(stderr, "%p: %d: AudioNode::~AudioNode() %d %d\n", this, nodeType(), m_normalRefCount, m_connectionRefCount);
     75 #endif
     76 }
     77 
     78 void AudioNode::initialize()
     79 {
     80     m_isInitialized = true;
     81 }
     82 
     83 void AudioNode::uninitialize()
     84 {
     85     m_isInitialized = false;
     86 }
     87 
     88 String AudioNode::nodeTypeName() const
     89 {
     90     switch (m_nodeType) {
     91     case NodeTypeDestination:
     92         return "AudioDestinationNode";
     93     case NodeTypeOscillator:
     94         return "OscillatorNode";
     95     case NodeTypeAudioBufferSource:
     96         return "AudioBufferSourceNode";
     97     case NodeTypeMediaElementAudioSource:
     98         return "MediaElementAudioSourceNode";
     99     case NodeTypeMediaStreamAudioDestination:
    100         return "MediaStreamAudioDestinationNode";
    101     case NodeTypeMediaStreamAudioSource:
    102         return "MediaStreamAudioSourceNode";
    103     case NodeTypeJavaScript:
    104         return "ScriptProcessorNode";
    105     case NodeTypeBiquadFilter:
    106         return "BiquadFilterNode";
    107     case NodeTypePanner:
    108         return "PannerNode";
    109     case NodeTypeConvolver:
    110         return "ConvolverNode";
    111     case NodeTypeDelay:
    112         return "DelayNode";
    113     case NodeTypeGain:
    114         return "GainNode";
    115     case NodeTypeChannelSplitter:
    116         return "ChannelSplitterNode";
    117     case NodeTypeChannelMerger:
    118         return "ChannelMergerNode";
    119     case NodeTypeAnalyser:
    120         return "AnalyserNode";
    121     case NodeTypeDynamicsCompressor:
    122         return "DynamicsCompressorNode";
    123     case NodeTypeWaveShaper:
    124         return "WaveShaperNode";
    125     case NodeTypeUnknown:
    126     case NodeTypeEnd:
    127     default:
    128         ASSERT_NOT_REACHED();
    129         return "UnknownNode";
    130     }
    131 }
    132 
    133 void AudioNode::setNodeType(NodeType type)
    134 {
    135     m_nodeType = type;
    136 
    137 #if DEBUG_AUDIONODE_REFERENCES
    138     ++s_nodeCount[type];
    139 #endif
    140 }
    141 
    142 void AudioNode::lazyInitialize()
    143 {
    144     if (!isInitialized())
    145         initialize();
    146 }
    147 
    148 void AudioNode::addInput(PassOwnPtr<AudioNodeInput> input)
    149 {
    150     m_inputs.append(input);
    151 }
    152 
    153 void AudioNode::addOutput(PassOwnPtr<AudioNodeOutput> output)
    154 {
    155     m_outputs.append(output);
    156 }
    157 
    158 AudioNodeInput* AudioNode::input(unsigned i)
    159 {
    160     if (i < m_inputs.size())
    161         return m_inputs[i].get();
    162     return 0;
    163 }
    164 
    165 AudioNodeOutput* AudioNode::output(unsigned i)
    166 {
    167     if (i < m_outputs.size())
    168         return m_outputs[i].get();
    169     return 0;
    170 }
    171 
    172 void AudioNode::connect(AudioNode* destination, unsigned outputIndex, unsigned inputIndex, ExceptionState& exceptionState)
    173 {
    174     ASSERT(isMainThread());
    175     AudioContext::AutoLocker locker(context());
    176 
    177     if (!destination) {
    178         exceptionState.throwDOMException(
    179             SyntaxError,
    180             "invalid destination node.");
    181         return;
    182     }
    183 
    184     // Sanity check input and output indices.
    185     if (outputIndex >= numberOfOutputs()) {
    186         exceptionState.throwDOMException(
    187             IndexSizeError,
    188             "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
    189         return;
    190     }
    191 
    192     if (destination && inputIndex >= destination->numberOfInputs()) {
    193         exceptionState.throwDOMException(
    194             IndexSizeError,
    195             "input index (" + String::number(inputIndex) + ") exceeds number of inputs (" + String::number(destination->numberOfInputs()) + ").");
    196         return;
    197     }
    198 
    199     if (context() != destination->context()) {
    200         exceptionState.throwDOMException(
    201             SyntaxError,
    202             "cannot connect to a destination belonging to a different audio context.");
    203         return;
    204     }
    205 
    206     AudioNodeInput* input = destination->input(inputIndex);
    207     AudioNodeOutput* output = this->output(outputIndex);
    208     input->connect(output);
    209 
    210     // Let context know that a connection has been made.
    211     context()->incrementConnectionCount();
    212 }
    213 
    214 void AudioNode::connect(AudioParam* param, unsigned outputIndex, ExceptionState& exceptionState)
    215 {
    216     ASSERT(isMainThread());
    217     AudioContext::AutoLocker locker(context());
    218 
    219     if (!param) {
    220         exceptionState.throwDOMException(
    221             SyntaxError,
    222             "invalid AudioParam.");
    223         return;
    224     }
    225 
    226     if (outputIndex >= numberOfOutputs()) {
    227         exceptionState.throwDOMException(
    228             IndexSizeError,
    229             "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
    230         return;
    231     }
    232 
    233     if (context() != param->context()) {
    234         exceptionState.throwDOMException(
    235             SyntaxError,
    236             "cannot connect to an AudioParam belonging to a different audio context.");
    237         return;
    238     }
    239 
    240     AudioNodeOutput* output = this->output(outputIndex);
    241     param->connect(output);
    242 }
    243 
    244 void AudioNode::disconnect(unsigned outputIndex, ExceptionState& exceptionState)
    245 {
    246     ASSERT(isMainThread());
    247     AudioContext::AutoLocker locker(context());
    248 
    249     // Sanity check input and output indices.
    250     if (outputIndex >= numberOfOutputs()) {
    251         exceptionState.throwDOMException(
    252             IndexSizeError,
    253             "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
    254         return;
    255     }
    256 
    257     AudioNodeOutput* output = this->output(outputIndex);
    258     output->disconnectAll();
    259 }
    260 
    261 unsigned long AudioNode::channelCount()
    262 {
    263     return m_channelCount;
    264 }
    265 
    266 void AudioNode::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
    267 {
    268     ASSERT(isMainThread());
    269     AudioContext::AutoLocker locker(context());
    270 
    271     if (channelCount > 0 && channelCount <= AudioContext::maxNumberOfChannels()) {
    272         if (m_channelCount != channelCount) {
    273             m_channelCount = channelCount;
    274             if (m_channelCountMode != Max)
    275                 updateChannelsForInputs();
    276         }
    277     } else {
    278         exceptionState.throwDOMException(
    279             NotSupportedError,
    280             "channel count (" + String::number(channelCount) + ") must be between 1 and " + String::number(AudioContext::maxNumberOfChannels()) + ".");
    281     }
    282 }
    283 
    284 String AudioNode::channelCountMode()
    285 {
    286     switch (m_channelCountMode) {
    287     case Max:
    288         return "max";
    289     case ClampedMax:
    290         return "clamped-max";
    291     case Explicit:
    292         return "explicit";
    293     }
    294     ASSERT_NOT_REACHED();
    295     return "";
    296 }
    297 
    298 void AudioNode::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
    299 {
    300     ASSERT(isMainThread());
    301     AudioContext::AutoLocker locker(context());
    302 
    303     ChannelCountMode oldMode = m_channelCountMode;
    304 
    305     if (mode == "max") {
    306         m_channelCountMode = Max;
    307     } else if (mode == "clamped-max") {
    308         m_channelCountMode = ClampedMax;
    309     } else if (mode == "explicit") {
    310         m_channelCountMode = Explicit;
    311     } else {
    312         exceptionState.throwDOMException(
    313             InvalidStateError,
    314             "invalid mode '" + mode + "'; must be 'max', 'clamped-max', or 'explicit'.");
    315     }
    316 
    317     if (m_channelCountMode != oldMode)
    318         updateChannelsForInputs();
    319 }
    320 
    321 String AudioNode::channelInterpretation()
    322 {
    323     switch (m_channelInterpretation) {
    324     case AudioBus::Speakers:
    325         return "speakers";
    326     case AudioBus::Discrete:
    327         return "discrete";
    328     }
    329     ASSERT_NOT_REACHED();
    330     return "";
    331 }
    332 
    333 void AudioNode::setChannelInterpretation(const String& interpretation, ExceptionState& exceptionState)
    334 {
    335     ASSERT(isMainThread());
    336     AudioContext::AutoLocker locker(context());
    337 
    338     if (interpretation == "speakers") {
    339         m_channelInterpretation = AudioBus::Speakers;
    340     } else if (interpretation == "discrete") {
    341         m_channelInterpretation = AudioBus::Discrete;
    342     } else {
    343         exceptionState.throwDOMException(
    344             InvalidStateError,
    345             "invalid interpretation '" + interpretation + "'; must be 'speakers' or 'discrete'.");
    346     }
    347 }
    348 
    349 void AudioNode::updateChannelsForInputs()
    350 {
    351     for (unsigned i = 0; i < m_inputs.size(); ++i)
    352         input(i)->changedOutputs();
    353 }
    354 
    355 const AtomicString& AudioNode::interfaceName() const
    356 {
    357     return EventTargetNames::AudioNode;
    358 }
    359 
    360 ExecutionContext* AudioNode::executionContext() const
    361 {
    362     return const_cast<AudioNode*>(this)->context()->executionContext();
    363 }
    364 
    365 void AudioNode::processIfNecessary(size_t framesToProcess)
    366 {
    367     ASSERT(context()->isAudioThread());
    368 
    369     if (!isInitialized())
    370         return;
    371 
    372     // Ensure that we only process once per rendering quantum.
    373     // This handles the "fanout" problem where an output is connected to multiple inputs.
    374     // The first time we're called during this time slice we process, but after that we don't want to re-process,
    375     // instead our output(s) will already have the results cached in their bus;
    376     double currentTime = context()->currentTime();
    377     if (m_lastProcessingTime != currentTime) {
    378         m_lastProcessingTime = currentTime; // important to first update this time because of feedback loops in the rendering graph
    379 
    380         pullInputs(framesToProcess);
    381 
    382         bool silentInputs = inputsAreSilent();
    383         if (!silentInputs)
    384             m_lastNonSilentTime = (context()->currentSampleFrame() + framesToProcess) / static_cast<double>(m_sampleRate);
    385 
    386         if (silentInputs && propagatesSilence())
    387             silenceOutputs();
    388         else {
    389             process(framesToProcess);
    390             unsilenceOutputs();
    391         }
    392     }
    393 }
    394 
    395 void AudioNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
    396 {
    397     ASSERT(context()->isAudioThread() && context()->isGraphOwner());
    398 
    399     ASSERT(m_inputs.contains(input));
    400     if (!m_inputs.contains(input))
    401         return;
    402 
    403     input->updateInternalBus();
    404 }
    405 
    406 bool AudioNode::propagatesSilence() const
    407 {
    408     return m_lastNonSilentTime + latencyTime() + tailTime() < context()->currentTime();
    409 }
    410 
    411 void AudioNode::pullInputs(size_t framesToProcess)
    412 {
    413     ASSERT(context()->isAudioThread());
    414 
    415     // Process all of the AudioNodes connected to our inputs.
    416     for (unsigned i = 0; i < m_inputs.size(); ++i)
    417         input(i)->pull(0, framesToProcess);
    418 }
    419 
    420 bool AudioNode::inputsAreSilent()
    421 {
    422     for (unsigned i = 0; i < m_inputs.size(); ++i) {
    423         if (!input(i)->bus()->isSilent())
    424             return false;
    425     }
    426     return true;
    427 }
    428 
    429 void AudioNode::silenceOutputs()
    430 {
    431     for (unsigned i = 0; i < m_outputs.size(); ++i)
    432         output(i)->bus()->zero();
    433 }
    434 
    435 void AudioNode::unsilenceOutputs()
    436 {
    437     for (unsigned i = 0; i < m_outputs.size(); ++i)
    438         output(i)->bus()->clearSilentFlag();
    439 }
    440 
    441 void AudioNode::enableOutputsIfNecessary()
    442 {
    443     if (m_isDisabled && m_connectionRefCount > 0) {
    444         ASSERT(isMainThread());
    445         AudioContext::AutoLocker locker(context());
    446 
    447         m_isDisabled = false;
    448         for (unsigned i = 0; i < m_outputs.size(); ++i)
    449             output(i)->enable();
    450     }
    451 }
    452 
    453 void AudioNode::disableOutputsIfNecessary()
    454 {
    455     // Disable outputs if appropriate. We do this if the number of connections is 0 or 1. The case
    456     // of 0 is from finishDeref() where there are no connections left. The case of 1 is from
    457     // AudioNodeInput::disable() where we want to disable outputs when there's only one connection
    458     // left because we're ready to go away, but can't quite yet.
    459     if (m_connectionRefCount <= 1 && !m_isDisabled) {
    460         // Still may have JavaScript references, but no more "active" connection references, so put all of our outputs in a "dormant" disabled state.
    461         // Garbage collection may take a very long time after this time, so the "dormant" disabled nodes should not bog down the rendering...
    462 
    463         // As far as JavaScript is concerned, our outputs must still appear to be connected.
    464         // But internally our outputs should be disabled from the inputs they're connected to.
    465         // disable() can recursively deref connections (and call disable()) down a whole chain of connected nodes.
    466 
    467         // FIXME: we special case the convolver and delay since they have a significant tail-time and shouldn't be disconnected simply
    468         // because they no longer have any input connections. This needs to be handled more generally where AudioNodes have
    469         // a tailTime attribute. Then the AudioNode only needs to remain "active" for tailTime seconds after there are no
    470         // longer any active connections.
    471         if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) {
    472             m_isDisabled = true;
    473             for (unsigned i = 0; i < m_outputs.size(); ++i)
    474                 output(i)->disable();
    475         }
    476     }
    477 }
    478 
    479 void AudioNode::ref(RefType refType)
    480 {
    481     switch (refType) {
    482     case RefTypeNormal:
    483         atomicIncrement(&m_normalRefCount);
    484         break;
    485     case RefTypeConnection:
    486         atomicIncrement(&m_connectionRefCount);
    487         break;
    488     default:
    489         ASSERT_NOT_REACHED();
    490     }
    491 
    492 #if DEBUG_AUDIONODE_REFERENCES
    493     fprintf(stderr, "%p: %d: AudioNode::ref(%d) %d %d\n", this, nodeType(), refType, m_normalRefCount, m_connectionRefCount);
    494 #endif
    495 
    496     // See the disabling code in finishDeref() below. This handles the case where a node
    497     // is being re-connected after being used at least once and disconnected.
    498     // In this case, we need to re-enable.
    499     if (refType == RefTypeConnection)
    500         enableOutputsIfNecessary();
    501 }
    502 
    503 void AudioNode::deref(RefType refType)
    504 {
    505     // The actually work for deref happens completely within the audio context's graph lock.
    506     // In the case of the audio thread, we must use a tryLock to avoid glitches.
    507     bool hasLock = false;
    508     bool mustReleaseLock = false;
    509 
    510     if (context()->isAudioThread()) {
    511         // Real-time audio thread must not contend lock (to avoid glitches).
    512         hasLock = context()->tryLock(mustReleaseLock);
    513     } else {
    514         context()->lock(mustReleaseLock);
    515         hasLock = true;
    516     }
    517 
    518     if (hasLock) {
    519         // This is where the real deref work happens.
    520         finishDeref(refType);
    521 
    522         if (mustReleaseLock)
    523             context()->unlock();
    524     } else {
    525         // We were unable to get the lock, so put this in a list to finish up later.
    526         ASSERT(context()->isAudioThread());
    527         ASSERT(refType == RefTypeConnection);
    528         context()->addDeferredFinishDeref(this);
    529     }
    530 
    531     // Once AudioContext::uninitialize() is called there's no more chances for deleteMarkedNodes() to get called, so we call here.
    532     // We can't call in AudioContext::~AudioContext() since it will never be called as long as any AudioNode is alive
    533     // because AudioNodes keep a reference to the context.
    534     if (context()->isAudioThreadFinished())
    535         context()->deleteMarkedNodes();
    536 }
    537 
    538 void AudioNode::finishDeref(RefType refType)
    539 {
    540     ASSERT(context()->isGraphOwner());
    541 
    542     switch (refType) {
    543     case RefTypeNormal:
    544         ASSERT(m_normalRefCount > 0);
    545         atomicDecrement(&m_normalRefCount);
    546         break;
    547     case RefTypeConnection:
    548         ASSERT(m_connectionRefCount > 0);
    549         atomicDecrement(&m_connectionRefCount);
    550         break;
    551     default:
    552         ASSERT_NOT_REACHED();
    553     }
    554 
    555 #if DEBUG_AUDIONODE_REFERENCES
    556     fprintf(stderr, "%p: %d: AudioNode::deref(%d) %d %d\n", this, nodeType(), refType, m_normalRefCount, m_connectionRefCount);
    557 #endif
    558 
    559     if (!m_connectionRefCount) {
    560         if (!m_normalRefCount) {
    561             if (!m_isMarkedForDeletion) {
    562                 // All references are gone - we need to go away.
    563                 for (unsigned i = 0; i < m_outputs.size(); ++i)
    564                     output(i)->disconnectAll(); // This will deref() nodes we're connected to.
    565 
    566                 // Mark for deletion at end of each render quantum or when context shuts down.
    567                 context()->markForDeletion(this);
    568                 m_isMarkedForDeletion = true;
    569             }
    570         } else if (refType == RefTypeConnection)
    571             disableOutputsIfNecessary();
    572     }
    573 }
    574 
    575 #if DEBUG_AUDIONODE_REFERENCES
    576 
    577 bool AudioNode::s_isNodeCountInitialized = false;
    578 int AudioNode::s_nodeCount[NodeTypeEnd];
    579 
    580 void AudioNode::printNodeCounts()
    581 {
    582     fprintf(stderr, "\n\n");
    583     fprintf(stderr, "===========================\n");
    584     fprintf(stderr, "AudioNode: reference counts\n");
    585     fprintf(stderr, "===========================\n");
    586 
    587     for (unsigned i = 0; i < NodeTypeEnd; ++i)
    588         fprintf(stderr, "%d: %d\n", i, s_nodeCount[i]);
    589 
    590     fprintf(stderr, "===========================\n\n\n");
    591 }
    592 
    593 #endif // DEBUG_AUDIONODE_REFERENCES
    594 
    595 } // namespace WebCore
    596 
    597 #endif // ENABLE(WEB_AUDIO)
    598