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