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