• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AudioNode(AudioContext * context,float sampleRate)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 
~AudioNode()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 
initialize()82 void AudioNode::initialize()
83 {
84     m_isInitialized = true;
85 }
86 
uninitialize()87 void AudioNode::uninitialize()
88 {
89     m_isInitialized = false;
90 }
91 
dispose()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 
nodeTypeName() const104 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 
setNodeType(NodeType type)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 
addInput()159 void AudioNode::addInput()
160 {
161     m_inputs.append(AudioNodeInput::create(*this));
162 }
163 
addOutput(AudioNodeOutput * output)164 void AudioNode::addOutput(AudioNodeOutput* output)
165 {
166     m_outputs.append(output);
167 }
168 
input(unsigned i)169 AudioNodeInput* AudioNode::input(unsigned i)
170 {
171     if (i < m_inputs.size())
172         return m_inputs[i].get();
173     return 0;
174 }
175 
output(unsigned i)176 AudioNodeOutput* AudioNode::output(unsigned i)
177 {
178     if (i < m_outputs.size())
179         return m_outputs[i].get();
180     return 0;
181 }
182 
connect(AudioNode * destination,unsigned outputIndex,unsigned inputIndex,ExceptionState & exceptionState)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 
connect(AudioParam * param,unsigned outputIndex,ExceptionState & exceptionState)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 
disconnect(unsigned outputIndex,ExceptionState & exceptionState)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 
channelCount()270 unsigned long AudioNode::channelCount()
271 {
272     return m_channelCount;
273 }
274 
setChannelCount(unsigned long channelCount,ExceptionState & exceptionState)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 
channelCountMode()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 
setChannelCountMode(const String & mode,ExceptionState & exceptionState)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 
channelInterpretation()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 
setChannelInterpretation(const String & interpretation,ExceptionState & exceptionState)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 
updateChannelsForInputs()354 void AudioNode::updateChannelsForInputs()
355 {
356     for (unsigned i = 0; i < m_inputs.size(); ++i)
357         input(i)->changedOutputs();
358 }
359 
interfaceName() const360 const AtomicString& AudioNode::interfaceName() const
361 {
362     return EventTargetNames::AudioNode;
363 }
364 
executionContext() const365 ExecutionContext* AudioNode::executionContext() const
366 {
367     return const_cast<AudioNode*>(this)->context()->executionContext();
368 }
369 
processIfNecessary(size_t framesToProcess)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 
checkNumberOfChannelsForInput(AudioNodeInput * input)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 
propagatesSilence() const411 bool AudioNode::propagatesSilence() const
412 {
413     return m_lastNonSilentTime + latencyTime() + tailTime() < context()->currentTime();
414 }
415 
pullInputs(size_t framesToProcess)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 
inputsAreSilent()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 
silenceOutputs()434 void AudioNode::silenceOutputs()
435 {
436     for (unsigned i = 0; i < m_outputs.size(); ++i)
437         output(i)->bus()->zero();
438 }
439 
unsilenceOutputs()440 void AudioNode::unsilenceOutputs()
441 {
442     for (unsigned i = 0; i < m_outputs.size(); ++i)
443         output(i)->bus()->clearSilentFlag();
444 }
445 
enableOutputsIfNecessary()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 
disableOutputsIfNecessary()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 
makeConnection()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 
breakConnection()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 
breakConnectionWithLock()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 
printNodeCounts()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 
trace(Visitor * visitor)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 
updateChannelCountMode()568 void AudioNode::updateChannelCountMode()
569 {
570     m_channelCountMode = m_newChannelCountMode;
571     updateChannelsForInputs();
572 }
573 
574 } // namespace blink
575 
576 #endif // ENABLE(WEB_AUDIO)
577