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/AudioNodeInput.h"
     30 
     31 #include "modules/webaudio/AudioContext.h"
     32 #include "modules/webaudio/AudioNode.h"
     33 #include "modules/webaudio/AudioNodeOutput.h"
     34 #include <algorithm>
     35 
     36 using namespace std;
     37 
     38 namespace WebCore {
     39 
     40 AudioNodeInput::AudioNodeInput(AudioNode* node)
     41     : AudioSummingJunction(node->context())
     42     , m_node(node)
     43 {
     44     // Set to mono by default.
     45     m_internalSummingBus = AudioBus::create(1, AudioNode::ProcessingSizeInFrames);
     46 }
     47 
     48 void AudioNodeInput::connect(AudioNodeOutput* output)
     49 {
     50     ASSERT(context()->isGraphOwner());
     51 
     52     ASSERT(output && node());
     53     if (!output || !node())
     54         return;
     55 
     56     // Check if we're already connected to this output.
     57     if (m_outputs.contains(output))
     58         return;
     59 
     60     output->addInput(this);
     61     m_outputs.add(output);
     62     changedOutputs();
     63 
     64     // Sombody has just connected to us, so count it as a reference.
     65     node()->ref(AudioNode::RefTypeConnection);
     66 }
     67 
     68 void AudioNodeInput::disconnect(AudioNodeOutput* output)
     69 {
     70     ASSERT(context()->isGraphOwner());
     71 
     72     ASSERT(output && node());
     73     if (!output || !node())
     74         return;
     75 
     76     // First try to disconnect from "active" connections.
     77     if (m_outputs.contains(output)) {
     78         m_outputs.remove(output);
     79         changedOutputs();
     80         output->removeInput(this);
     81         node()->deref(AudioNode::RefTypeConnection); // Note: it's important to return immediately after all deref() calls since the node may be deleted.
     82         return;
     83     }
     84 
     85     // Otherwise, try to disconnect from disabled connections.
     86     if (m_disabledOutputs.contains(output)) {
     87         m_disabledOutputs.remove(output);
     88         output->removeInput(this);
     89         node()->deref(AudioNode::RefTypeConnection); // Note: it's important to return immediately after all deref() calls since the node may be deleted.
     90         return;
     91     }
     92 
     93     ASSERT_NOT_REACHED();
     94 }
     95 
     96 void AudioNodeInput::disable(AudioNodeOutput* output)
     97 {
     98     ASSERT(context()->isGraphOwner());
     99 
    100     ASSERT(output && node());
    101     if (!output || !node())
    102         return;
    103 
    104     ASSERT(m_outputs.contains(output));
    105 
    106     m_disabledOutputs.add(output);
    107     m_outputs.remove(output);
    108     changedOutputs();
    109 
    110     // Propagate disabled state to outputs.
    111     node()->disableOutputsIfNecessary();
    112 }
    113 
    114 void AudioNodeInput::enable(AudioNodeOutput* output)
    115 {
    116     ASSERT(context()->isGraphOwner());
    117 
    118     ASSERT(output && node());
    119     if (!output || !node())
    120         return;
    121 
    122     ASSERT(m_disabledOutputs.contains(output));
    123 
    124     // Move output from disabled list to active list.
    125     m_outputs.add(output);
    126     m_disabledOutputs.remove(output);
    127     changedOutputs();
    128 
    129     // Propagate enabled state to outputs.
    130     node()->enableOutputsIfNecessary();
    131 }
    132 
    133 void AudioNodeInput::didUpdate()
    134 {
    135     node()->checkNumberOfChannelsForInput(this);
    136 }
    137 
    138 void AudioNodeInput::updateInternalBus()
    139 {
    140     ASSERT(context()->isAudioThread() && context()->isGraphOwner());
    141 
    142     unsigned numberOfInputChannels = numberOfChannels();
    143 
    144     if (numberOfInputChannels == m_internalSummingBus->numberOfChannels())
    145         return;
    146 
    147     m_internalSummingBus = AudioBus::create(numberOfInputChannels, AudioNode::ProcessingSizeInFrames);
    148 }
    149 
    150 unsigned AudioNodeInput::numberOfChannels() const
    151 {
    152     AudioNode::ChannelCountMode mode = node()->internalChannelCountMode();
    153     if (mode == AudioNode::Explicit)
    154         return node()->channelCount();
    155 
    156     // Find the number of channels of the connection with the largest number of channels.
    157     unsigned maxChannels = 1; // one channel is the minimum allowed
    158 
    159     for (HashSet<AudioNodeOutput*>::iterator i = m_outputs.begin(); i != m_outputs.end(); ++i) {
    160         AudioNodeOutput* output = *i;
    161         // Use output()->numberOfChannels() instead of output->bus()->numberOfChannels(),
    162         // because the calling of AudioNodeOutput::bus() is not safe here.
    163         maxChannels = max(maxChannels, output->numberOfChannels());
    164     }
    165 
    166     if (mode == AudioNode::ClampedMax)
    167         maxChannels = min(maxChannels, static_cast<unsigned>(node()->channelCount()));
    168 
    169     return maxChannels;
    170 }
    171 
    172 AudioBus* AudioNodeInput::bus()
    173 {
    174     ASSERT(context()->isAudioThread());
    175 
    176     // Handle single connection specially to allow for in-place processing.
    177     if (numberOfRenderingConnections() == 1 && node()->internalChannelCountMode() == AudioNode::Max)
    178         return renderingOutput(0)->bus();
    179 
    180     // Multiple connections case or complex ChannelCountMode (or no connections).
    181     return internalSummingBus();
    182 }
    183 
    184 AudioBus* AudioNodeInput::internalSummingBus()
    185 {
    186     ASSERT(context()->isAudioThread());
    187 
    188     return m_internalSummingBus.get();
    189 }
    190 
    191 void AudioNodeInput::sumAllConnections(AudioBus* summingBus, size_t framesToProcess)
    192 {
    193     ASSERT(context()->isAudioThread());
    194 
    195     // We shouldn't be calling this method if there's only one connection, since it's less efficient.
    196     ASSERT(numberOfRenderingConnections() > 1 || node()->internalChannelCountMode() != AudioNode::Max);
    197 
    198     ASSERT(summingBus);
    199     if (!summingBus)
    200         return;
    201 
    202     summingBus->zero();
    203 
    204     AudioBus::ChannelInterpretation interpretation = node()->internalChannelInterpretation();
    205 
    206     for (unsigned i = 0; i < numberOfRenderingConnections(); ++i) {
    207         AudioNodeOutput* output = renderingOutput(i);
    208         ASSERT(output);
    209 
    210         // Render audio from this output.
    211         AudioBus* connectionBus = output->pull(0, framesToProcess);
    212 
    213         // Sum, with unity-gain.
    214         summingBus->sumFrom(*connectionBus, interpretation);
    215     }
    216 }
    217 
    218 AudioBus* AudioNodeInput::pull(AudioBus* inPlaceBus, size_t framesToProcess)
    219 {
    220     ASSERT(context()->isAudioThread());
    221 
    222     // Handle single connection case.
    223     if (numberOfRenderingConnections() == 1 && node()->internalChannelCountMode() == AudioNode::Max) {
    224         // The output will optimize processing using inPlaceBus if it's able.
    225         AudioNodeOutput* output = this->renderingOutput(0);
    226         return output->pull(inPlaceBus, framesToProcess);
    227     }
    228 
    229     AudioBus* internalSummingBus = this->internalSummingBus();
    230 
    231     if (!numberOfRenderingConnections()) {
    232         // At least, generate silence if we're not connected to anything.
    233         // FIXME: if we wanted to get fancy, we could propagate a 'silent hint' here to optimize the downstream graph processing.
    234         internalSummingBus->zero();
    235         return internalSummingBus;
    236     }
    237 
    238     // Handle multiple connections case.
    239     sumAllConnections(internalSummingBus, framesToProcess);
    240 
    241     return internalSummingBus;
    242 }
    243 
    244 } // namespace WebCore
    245 
    246 #endif // ENABLE(WEB_AUDIO)
    247