2 * Copyright (C) 2010, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "modules/webaudio/AudioNode.h"
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"
40 #if DEBUG_AUDIONODE_REFERENCES
46 unsigned AudioNode::s_instanceCount = 0;
48 AudioNode::AudioNode(AudioContext* context, float sampleRate)
49 : m_isInitialized(false)
50 , m_nodeType(NodeTypeUnknown)
52 , m_sampleRate(sampleRate)
53 , m_lastProcessingTime(-1)
54 , m_lastNonSilentTime(-1)
55 , m_connectionRefCount(0)
58 , m_channelCountMode(Max)
59 , m_channelInterpretation(AudioBus::Speakers)
60 , m_newChannelCountMode(Max)
62 m_context->registerLiveNode(*this);
63 #if DEBUG_AUDIONODE_REFERENCES
64 if (!s_isNodeCountInitialized) {
65 s_isNodeCountInitialized = true;
66 atexit(AudioNode::printNodeCounts);
72 AudioNode::~AudioNode()
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()]);
82 void AudioNode::initialize()
84 m_isInitialized = true;
87 void AudioNode::uninitialize()
89 m_isInitialized = false;
92 void AudioNode::clearInternalStateWhenDisabled()
96 void AudioNode::dispose()
98 ASSERT(isMainThread());
99 ASSERT(context()->isGraphOwner());
101 context()->removeChangedChannelCountMode(this);
102 context()->removeAutomaticPullNode(this);
103 context()->disposeOutputs(*this);
104 for (unsigned i = 0; i < m_outputs.size(); ++i)
105 output(i)->disconnectAll();
108 String AudioNode::nodeTypeName() const
110 switch (m_nodeType) {
111 case NodeTypeDestination:
112 return "AudioDestinationNode";
113 case NodeTypeOscillator:
114 return "OscillatorNode";
115 case NodeTypeAudioBufferSource:
116 return "AudioBufferSourceNode";
117 case NodeTypeMediaElementAudioSource:
118 return "MediaElementAudioSourceNode";
119 case NodeTypeMediaStreamAudioDestination:
120 return "MediaStreamAudioDestinationNode";
121 case NodeTypeMediaStreamAudioSource:
122 return "MediaStreamAudioSourceNode";
123 case NodeTypeJavaScript:
124 return "ScriptProcessorNode";
125 case NodeTypeBiquadFilter:
126 return "BiquadFilterNode";
129 case NodeTypeConvolver:
130 return "ConvolverNode";
135 case NodeTypeChannelSplitter:
136 return "ChannelSplitterNode";
137 case NodeTypeChannelMerger:
138 return "ChannelMergerNode";
139 case NodeTypeAnalyser:
140 return "AnalyserNode";
141 case NodeTypeDynamicsCompressor:
142 return "DynamicsCompressorNode";
143 case NodeTypeWaveShaper:
144 return "WaveShaperNode";
145 case NodeTypeUnknown:
148 ASSERT_NOT_REACHED();
149 return "UnknownNode";
153 void AudioNode::setNodeType(NodeType type)
157 #if DEBUG_AUDIONODE_REFERENCES
159 fprintf(stderr, "%p: %2d: AudioNode::AudioNode [%3d]\n", this, nodeType(), s_nodeCount[nodeType()]);
163 void AudioNode::addInput()
165 m_inputs.append(AudioNodeInput::create(*this));
168 void AudioNode::addOutput(AudioNodeOutput* output)
170 m_outputs.append(output);
173 AudioNodeInput* AudioNode::input(unsigned i)
175 if (i < m_inputs.size())
176 return m_inputs[i].get();
180 AudioNodeOutput* AudioNode::output(unsigned i)
182 if (i < m_outputs.size())
183 return m_outputs[i].get();
187 void AudioNode::connect(AudioNode* destination, unsigned outputIndex, unsigned inputIndex, ExceptionState& exceptionState)
189 ASSERT(isMainThread());
190 AudioContext::AutoLocker locker(context());
193 exceptionState.throwDOMException(
195 "invalid destination node.");
199 // Sanity check input and output indices.
200 if (outputIndex >= numberOfOutputs()) {
201 exceptionState.throwDOMException(
203 "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
207 if (destination && inputIndex >= destination->numberOfInputs()) {
208 exceptionState.throwDOMException(
210 "input index (" + String::number(inputIndex) + ") exceeds number of inputs (" + String::number(destination->numberOfInputs()) + ").");
214 if (context() != destination->context()) {
215 exceptionState.throwDOMException(
217 "cannot connect to a destination belonging to a different audio context.");
221 AudioNodeInput* input = destination->input(inputIndex);
222 input->connect(*output(outputIndex));
224 // Let context know that a connection has been made.
225 context()->incrementConnectionCount();
228 void AudioNode::connect(AudioParam* param, unsigned outputIndex, ExceptionState& exceptionState)
230 ASSERT(isMainThread());
231 AudioContext::AutoLocker locker(context());
234 exceptionState.throwDOMException(
236 "invalid AudioParam.");
240 if (outputIndex >= numberOfOutputs()) {
241 exceptionState.throwDOMException(
243 "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
247 if (context() != param->context()) {
248 exceptionState.throwDOMException(
250 "cannot connect to an AudioParam belonging to a different audio context.");
254 param->connect(*output(outputIndex));
257 void AudioNode::disconnect(unsigned outputIndex, ExceptionState& exceptionState)
259 ASSERT(isMainThread());
260 AudioContext::AutoLocker locker(context());
262 // Sanity check input and output indices.
263 if (outputIndex >= numberOfOutputs()) {
264 exceptionState.throwDOMException(
266 "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
270 AudioNodeOutput* output = this->output(outputIndex);
271 output->disconnectAll();
274 unsigned long AudioNode::channelCount()
276 return m_channelCount;
279 void AudioNode::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
281 ASSERT(isMainThread());
282 AudioContext::AutoLocker locker(context());
284 if (channelCount > 0 && channelCount <= AudioContext::maxNumberOfChannels()) {
285 if (m_channelCount != channelCount) {
286 m_channelCount = channelCount;
287 if (m_channelCountMode != Max)
288 updateChannelsForInputs();
291 exceptionState.throwDOMException(
293 "channel count (" + String::number(channelCount) + ") must be between 1 and " + String::number(AudioContext::maxNumberOfChannels()) + ".");
297 String AudioNode::channelCountMode()
299 switch (m_channelCountMode) {
303 return "clamped-max";
307 ASSERT_NOT_REACHED();
311 void AudioNode::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
313 ASSERT(isMainThread());
314 AudioContext::AutoLocker locker(context());
316 ChannelCountMode oldMode = m_channelCountMode;
319 m_newChannelCountMode = Max;
320 } else if (mode == "clamped-max") {
321 m_newChannelCountMode = ClampedMax;
322 } else if (mode == "explicit") {
323 m_newChannelCountMode = Explicit;
325 ASSERT_NOT_REACHED();
328 if (m_newChannelCountMode != oldMode)
329 context()->addChangedChannelCountMode(this);
332 String AudioNode::channelInterpretation()
334 switch (m_channelInterpretation) {
335 case AudioBus::Speakers:
337 case AudioBus::Discrete:
340 ASSERT_NOT_REACHED();
344 void AudioNode::setChannelInterpretation(const String& interpretation, ExceptionState& exceptionState)
346 ASSERT(isMainThread());
347 AudioContext::AutoLocker locker(context());
349 if (interpretation == "speakers") {
350 m_channelInterpretation = AudioBus::Speakers;
351 } else if (interpretation == "discrete") {
352 m_channelInterpretation = AudioBus::Discrete;
354 ASSERT_NOT_REACHED();
358 void AudioNode::updateChannelsForInputs()
360 for (unsigned i = 0; i < m_inputs.size(); ++i)
361 input(i)->changedOutputs();
364 const AtomicString& AudioNode::interfaceName() const
366 return EventTargetNames::AudioNode;
369 ExecutionContext* AudioNode::executionContext() const
371 return const_cast<AudioNode*>(this)->context()->executionContext();
374 void AudioNode::processIfNecessary(size_t framesToProcess)
376 ASSERT(context()->isAudioThread());
378 if (!isInitialized())
381 // Ensure that we only process once per rendering quantum.
382 // This handles the "fanout" problem where an output is connected to multiple inputs.
383 // The first time we're called during this time slice we process, but after that we don't want to re-process,
384 // instead our output(s) will already have the results cached in their bus;
385 double currentTime = context()->currentTime();
386 if (m_lastProcessingTime != currentTime) {
387 m_lastProcessingTime = currentTime; // important to first update this time because of feedback loops in the rendering graph
389 pullInputs(framesToProcess);
391 bool silentInputs = inputsAreSilent();
393 m_lastNonSilentTime = (context()->currentSampleFrame() + framesToProcess) / static_cast<double>(m_sampleRate);
395 if (silentInputs && propagatesSilence())
398 process(framesToProcess);
404 void AudioNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
406 ASSERT(context()->isAudioThread() && context()->isGraphOwner());
408 ASSERT(m_inputs.contains(input));
409 if (!m_inputs.contains(input))
412 input->updateInternalBus();
415 bool AudioNode::propagatesSilence() const
417 return m_lastNonSilentTime + latencyTime() + tailTime() < context()->currentTime();
420 void AudioNode::pullInputs(size_t framesToProcess)
422 ASSERT(context()->isAudioThread());
424 // Process all of the AudioNodes connected to our inputs.
425 for (unsigned i = 0; i < m_inputs.size(); ++i)
426 input(i)->pull(0, framesToProcess);
429 bool AudioNode::inputsAreSilent()
431 for (unsigned i = 0; i < m_inputs.size(); ++i) {
432 if (!input(i)->bus()->isSilent())
438 void AudioNode::silenceOutputs()
440 for (unsigned i = 0; i < m_outputs.size(); ++i)
441 output(i)->bus()->zero();
444 void AudioNode::unsilenceOutputs()
446 for (unsigned i = 0; i < m_outputs.size(); ++i)
447 output(i)->bus()->clearSilentFlag();
450 void AudioNode::enableOutputsIfNecessary()
452 if (m_isDisabled && m_connectionRefCount > 0) {
453 ASSERT(isMainThread());
454 AudioContext::AutoLocker locker(context());
456 m_isDisabled = false;
457 for (unsigned i = 0; i < m_outputs.size(); ++i)
462 void AudioNode::disableOutputsIfNecessary()
464 // Disable outputs if appropriate. We do this if the number of connections is 0 or 1. The case
465 // of 0 is from deref() where there are no connections left. The case of 1 is from
466 // AudioNodeInput::disable() where we want to disable outputs when there's only one connection
467 // left because we're ready to go away, but can't quite yet.
468 if (m_connectionRefCount <= 1 && !m_isDisabled) {
469 // Still may have JavaScript references, but no more "active" connection references, so put all of our outputs in a "dormant" disabled state.
470 // Garbage collection may take a very long time after this time, so the "dormant" disabled nodes should not bog down the rendering...
472 // As far as JavaScript is concerned, our outputs must still appear to be connected.
473 // But internally our outputs should be disabled from the inputs they're connected to.
474 // disable() can recursively deref connections (and call disable()) down a whole chain of connected nodes.
476 // FIXME: we special case the convolver and delay since they have a significant tail-time and shouldn't be disconnected simply
477 // because they no longer have any input connections. This needs to be handled more generally where AudioNodes have
478 // a tailTime attribute. Then the AudioNode only needs to remain "active" for tailTime seconds after there are no
479 // longer any active connections.
480 if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) {
482 clearInternalStateWhenDisabled();
483 for (unsigned i = 0; i < m_outputs.size(); ++i)
484 output(i)->disable();
489 void AudioNode::makeConnection()
491 atomicIncrement(&m_connectionRefCount);
493 #if DEBUG_AUDIONODE_REFERENCES
494 fprintf(stderr, "%p: %2d: AudioNode::ref %3d [%3d]\n",
495 this, nodeType(), m_connectionRefCount, s_nodeCount[nodeType()]);
497 // See the disabling code in disableOutputsIfNecessary(). This handles
498 // the case where a node is being re-connected after being used at least
499 // once and disconnected. In this case, we need to re-enable.
500 enableOutputsIfNecessary();
503 void AudioNode::breakConnection()
505 // The actual work for deref happens completely within the audio context's
506 // graph lock. In the case of the audio thread, we must use a tryLock to
508 bool hasLock = false;
509 if (context()->isAudioThread()) {
510 // Real-time audio thread must not contend lock (to avoid glitches).
511 hasLock = context()->tryLock();
518 breakConnectionWithLock();
521 // We were unable to get the lock, so put this in a list to finish up
523 ASSERT(context()->isAudioThread());
524 context()->addDeferredBreakConnection(*this);
528 void AudioNode::breakConnectionWithLock()
530 atomicDecrement(&m_connectionRefCount);
532 #if DEBUG_AUDIONODE_REFERENCES
533 fprintf(stderr, "%p: %2d: AudioNode::deref %3d [%3d]\n",
534 this, nodeType(), m_connectionRefCount, s_nodeCount[nodeType()]);
537 if (!m_connectionRefCount)
538 disableOutputsIfNecessary();
541 #if DEBUG_AUDIONODE_REFERENCES
543 bool AudioNode::s_isNodeCountInitialized = false;
544 int AudioNode::s_nodeCount[NodeTypeEnd];
546 void AudioNode::printNodeCounts()
548 fprintf(stderr, "\n\n");
549 fprintf(stderr, "===========================\n");
550 fprintf(stderr, "AudioNode: reference counts\n");
551 fprintf(stderr, "===========================\n");
553 for (unsigned i = 0; i < NodeTypeEnd; ++i)
554 fprintf(stderr, "%2d: %d\n", i, s_nodeCount[i]);
556 fprintf(stderr, "===========================\n\n\n");
559 #endif // DEBUG_AUDIONODE_REFERENCES
561 void AudioNode::trace(Visitor* visitor)
563 visitor->trace(m_context);
564 visitor->trace(m_inputs);
565 visitor->trace(m_outputs);
566 EventTargetWithInlineData::trace(visitor);
569 void AudioNode::updateChannelCountMode()
571 m_channelCountMode = m_newChannelCountMode;
572 updateChannelsForInputs();
577 #endif // ENABLE(WEB_AUDIO)