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 44namespace WebCore { 45 46AudioNode::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 70AudioNode::~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 78void AudioNode::initialize() 79{ 80 m_isInitialized = true; 81} 82 83void AudioNode::uninitialize() 84{ 85 m_isInitialized = false; 86} 87 88String 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 133void AudioNode::setNodeType(NodeType type) 134{ 135 m_nodeType = type; 136 137#if DEBUG_AUDIONODE_REFERENCES 138 ++s_nodeCount[type]; 139#endif 140} 141 142void AudioNode::lazyInitialize() 143{ 144 if (!isInitialized()) 145 initialize(); 146} 147 148void AudioNode::addInput(PassOwnPtr<AudioNodeInput> input) 149{ 150 m_inputs.append(input); 151} 152 153void AudioNode::addOutput(PassOwnPtr<AudioNodeOutput> output) 154{ 155 m_outputs.append(output); 156} 157 158AudioNodeInput* AudioNode::input(unsigned i) 159{ 160 if (i < m_inputs.size()) 161 return m_inputs[i].get(); 162 return 0; 163} 164 165AudioNodeOutput* AudioNode::output(unsigned i) 166{ 167 if (i < m_outputs.size()) 168 return m_outputs[i].get(); 169 return 0; 170} 171 172void 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 214void 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 244void 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 261unsigned long AudioNode::channelCount() 262{ 263 return m_channelCount; 264} 265 266void 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 284String 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 298void 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 321String 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 333void 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 349void AudioNode::updateChannelsForInputs() 350{ 351 for (unsigned i = 0; i < m_inputs.size(); ++i) 352 input(i)->changedOutputs(); 353} 354 355const AtomicString& AudioNode::interfaceName() const 356{ 357 return EventTargetNames::AudioNode; 358} 359 360ExecutionContext* AudioNode::executionContext() const 361{ 362 return const_cast<AudioNode*>(this)->context()->executionContext(); 363} 364 365void 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 395void 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 406bool AudioNode::propagatesSilence() const 407{ 408 return m_lastNonSilentTime + latencyTime() + tailTime() < context()->currentTime(); 409} 410 411void 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 420bool 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 429void AudioNode::silenceOutputs() 430{ 431 for (unsigned i = 0; i < m_outputs.size(); ++i) 432 output(i)->bus()->zero(); 433} 434 435void AudioNode::unsilenceOutputs() 436{ 437 for (unsigned i = 0; i < m_outputs.size(); ++i) 438 output(i)->bus()->clearSilentFlag(); 439} 440 441void 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 453void 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 479void 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 503void 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 538void 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 577bool AudioNode::s_isNodeCountInitialized = false; 578int AudioNode::s_nodeCount[NodeTypeEnd]; 579 580void 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