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