Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / webaudio / AudioNode.cpp
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
44 namespace WebCore {
45
46 AudioNode::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
70 AudioNode::~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
78 void AudioNode::initialize()
79 {
80     m_isInitialized = true;
81 }
82
83 void AudioNode::uninitialize()
84 {
85     m_isInitialized = false;
86 }
87
88 String 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
133 void AudioNode::setNodeType(NodeType type)
134 {
135     m_nodeType = type;
136
137 #if DEBUG_AUDIONODE_REFERENCES
138     ++s_nodeCount[type];
139 #endif
140 }
141
142 void AudioNode::addInput(PassOwnPtr<AudioNodeInput> input)
143 {
144     m_inputs.append(input);
145 }
146
147 void AudioNode::addOutput(PassOwnPtr<AudioNodeOutput> output)
148 {
149     m_outputs.append(output);
150 }
151
152 AudioNodeInput* AudioNode::input(unsigned i)
153 {
154     if (i < m_inputs.size())
155         return m_inputs[i].get();
156     return 0;
157 }
158
159 AudioNodeOutput* AudioNode::output(unsigned i)
160 {
161     if (i < m_outputs.size())
162         return m_outputs[i].get();
163     return 0;
164 }
165
166 void AudioNode::connect(AudioNode* destination, unsigned outputIndex, unsigned inputIndex, ExceptionState& exceptionState)
167 {
168     ASSERT(isMainThread());
169     AudioContext::AutoLocker locker(context());
170
171     if (!destination) {
172         exceptionState.throwDOMException(
173             SyntaxError,
174             "invalid destination node.");
175         return;
176     }
177
178     // Sanity check input and output indices.
179     if (outputIndex >= numberOfOutputs()) {
180         exceptionState.throwDOMException(
181             IndexSizeError,
182             "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
183         return;
184     }
185
186     if (destination && inputIndex >= destination->numberOfInputs()) {
187         exceptionState.throwDOMException(
188             IndexSizeError,
189             "input index (" + String::number(inputIndex) + ") exceeds number of inputs (" + String::number(destination->numberOfInputs()) + ").");
190         return;
191     }
192
193     if (context() != destination->context()) {
194         exceptionState.throwDOMException(
195             SyntaxError,
196             "cannot connect to a destination belonging to a different audio context.");
197         return;
198     }
199
200     AudioNodeInput* input = destination->input(inputIndex);
201     AudioNodeOutput* output = this->output(outputIndex);
202     input->connect(output);
203
204     // Let context know that a connection has been made.
205     context()->incrementConnectionCount();
206 }
207
208 void AudioNode::connect(AudioParam* param, unsigned outputIndex, ExceptionState& exceptionState)
209 {
210     ASSERT(isMainThread());
211     AudioContext::AutoLocker locker(context());
212
213     if (!param) {
214         exceptionState.throwDOMException(
215             SyntaxError,
216             "invalid AudioParam.");
217         return;
218     }
219
220     if (outputIndex >= numberOfOutputs()) {
221         exceptionState.throwDOMException(
222             IndexSizeError,
223             "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
224         return;
225     }
226
227     if (context() != param->context()) {
228         exceptionState.throwDOMException(
229             SyntaxError,
230             "cannot connect to an AudioParam belonging to a different audio context.");
231         return;
232     }
233
234     AudioNodeOutput* output = this->output(outputIndex);
235     param->connect(output);
236 }
237
238 void AudioNode::disconnect(unsigned outputIndex, ExceptionState& exceptionState)
239 {
240     ASSERT(isMainThread());
241     AudioContext::AutoLocker locker(context());
242
243     // Sanity check input and output indices.
244     if (outputIndex >= numberOfOutputs()) {
245         exceptionState.throwDOMException(
246             IndexSizeError,
247             "output index (" + String::number(outputIndex) + ") exceeds number of outputs (" + String::number(numberOfOutputs()) + ").");
248         return;
249     }
250
251     AudioNodeOutput* output = this->output(outputIndex);
252     output->disconnectAll();
253 }
254
255 unsigned long AudioNode::channelCount()
256 {
257     return m_channelCount;
258 }
259
260 void AudioNode::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
261 {
262     ASSERT(isMainThread());
263     AudioContext::AutoLocker locker(context());
264
265     if (channelCount > 0 && channelCount <= AudioContext::maxNumberOfChannels()) {
266         if (m_channelCount != channelCount) {
267             m_channelCount = channelCount;
268             if (m_channelCountMode != Max)
269                 updateChannelsForInputs();
270         }
271     } else {
272         exceptionState.throwDOMException(
273             NotSupportedError,
274             "channel count (" + String::number(channelCount) + ") must be between 1 and " + String::number(AudioContext::maxNumberOfChannels()) + ".");
275     }
276 }
277
278 String AudioNode::channelCountMode()
279 {
280     switch (m_channelCountMode) {
281     case Max:
282         return "max";
283     case ClampedMax:
284         return "clamped-max";
285     case Explicit:
286         return "explicit";
287     }
288     ASSERT_NOT_REACHED();
289     return "";
290 }
291
292 void AudioNode::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
293 {
294     ASSERT(isMainThread());
295     AudioContext::AutoLocker locker(context());
296
297     ChannelCountMode oldMode = m_channelCountMode;
298
299     if (mode == "max") {
300         m_channelCountMode = Max;
301     } else if (mode == "clamped-max") {
302         m_channelCountMode = ClampedMax;
303     } else if (mode == "explicit") {
304         m_channelCountMode = Explicit;
305     } else {
306         exceptionState.throwDOMException(
307             InvalidStateError,
308             "invalid mode '" + mode + "'; must be 'max', 'clamped-max', or 'explicit'.");
309     }
310
311     if (m_channelCountMode != oldMode)
312         updateChannelsForInputs();
313 }
314
315 String AudioNode::channelInterpretation()
316 {
317     switch (m_channelInterpretation) {
318     case AudioBus::Speakers:
319         return "speakers";
320     case AudioBus::Discrete:
321         return "discrete";
322     }
323     ASSERT_NOT_REACHED();
324     return "";
325 }
326
327 void AudioNode::setChannelInterpretation(const String& interpretation, ExceptionState& exceptionState)
328 {
329     ASSERT(isMainThread());
330     AudioContext::AutoLocker locker(context());
331
332     if (interpretation == "speakers") {
333         m_channelInterpretation = AudioBus::Speakers;
334     } else if (interpretation == "discrete") {
335         m_channelInterpretation = AudioBus::Discrete;
336     } else {
337         exceptionState.throwDOMException(
338             InvalidStateError,
339             "invalid interpretation '" + interpretation + "'; must be 'speakers' or 'discrete'.");
340     }
341 }
342
343 void AudioNode::updateChannelsForInputs()
344 {
345     for (unsigned i = 0; i < m_inputs.size(); ++i)
346         input(i)->changedOutputs();
347 }
348
349 const AtomicString& AudioNode::interfaceName() const
350 {
351     return EventTargetNames::AudioNode;
352 }
353
354 ExecutionContext* AudioNode::executionContext() const
355 {
356     return const_cast<AudioNode*>(this)->context()->executionContext();
357 }
358
359 void AudioNode::processIfNecessary(size_t framesToProcess)
360 {
361     ASSERT(context()->isAudioThread());
362
363     if (!isInitialized())
364         return;
365
366     // Ensure that we only process once per rendering quantum.
367     // This handles the "fanout" problem where an output is connected to multiple inputs.
368     // The first time we're called during this time slice we process, but after that we don't want to re-process,
369     // instead our output(s) will already have the results cached in their bus;
370     double currentTime = context()->currentTime();
371     if (m_lastProcessingTime != currentTime) {
372         m_lastProcessingTime = currentTime; // important to first update this time because of feedback loops in the rendering graph
373
374         pullInputs(framesToProcess);
375
376         bool silentInputs = inputsAreSilent();
377         if (!silentInputs)
378             m_lastNonSilentTime = (context()->currentSampleFrame() + framesToProcess) / static_cast<double>(m_sampleRate);
379
380         if (silentInputs && propagatesSilence())
381             silenceOutputs();
382         else {
383             process(framesToProcess);
384             unsilenceOutputs();
385         }
386     }
387 }
388
389 void AudioNode::checkNumberOfChannelsForInput(AudioNodeInput* input)
390 {
391     ASSERT(context()->isAudioThread() && context()->isGraphOwner());
392
393     ASSERT(m_inputs.contains(input));
394     if (!m_inputs.contains(input))
395         return;
396
397     input->updateInternalBus();
398 }
399
400 bool AudioNode::propagatesSilence() const
401 {
402     return m_lastNonSilentTime + latencyTime() + tailTime() < context()->currentTime();
403 }
404
405 void AudioNode::pullInputs(size_t framesToProcess)
406 {
407     ASSERT(context()->isAudioThread());
408
409     // Process all of the AudioNodes connected to our inputs.
410     for (unsigned i = 0; i < m_inputs.size(); ++i)
411         input(i)->pull(0, framesToProcess);
412 }
413
414 bool AudioNode::inputsAreSilent()
415 {
416     for (unsigned i = 0; i < m_inputs.size(); ++i) {
417         if (!input(i)->bus()->isSilent())
418             return false;
419     }
420     return true;
421 }
422
423 void AudioNode::silenceOutputs()
424 {
425     for (unsigned i = 0; i < m_outputs.size(); ++i)
426         output(i)->bus()->zero();
427 }
428
429 void AudioNode::unsilenceOutputs()
430 {
431     for (unsigned i = 0; i < m_outputs.size(); ++i)
432         output(i)->bus()->clearSilentFlag();
433 }
434
435 void AudioNode::enableOutputsIfNecessary()
436 {
437     if (m_isDisabled && m_connectionRefCount > 0) {
438         ASSERT(isMainThread());
439         AudioContext::AutoLocker locker(context());
440
441         m_isDisabled = false;
442         for (unsigned i = 0; i < m_outputs.size(); ++i)
443             output(i)->enable();
444     }
445 }
446
447 void AudioNode::disableOutputsIfNecessary()
448 {
449     // Disable outputs if appropriate. We do this if the number of connections is 0 or 1. The case
450     // of 0 is from finishDeref() where there are no connections left. The case of 1 is from
451     // AudioNodeInput::disable() where we want to disable outputs when there's only one connection
452     // left because we're ready to go away, but can't quite yet.
453     if (m_connectionRefCount <= 1 && !m_isDisabled) {
454         // Still may have JavaScript references, but no more "active" connection references, so put all of our outputs in a "dormant" disabled state.
455         // Garbage collection may take a very long time after this time, so the "dormant" disabled nodes should not bog down the rendering...
456
457         // As far as JavaScript is concerned, our outputs must still appear to be connected.
458         // But internally our outputs should be disabled from the inputs they're connected to.
459         // disable() can recursively deref connections (and call disable()) down a whole chain of connected nodes.
460
461         // FIXME: we special case the convolver and delay since they have a significant tail-time and shouldn't be disconnected simply
462         // because they no longer have any input connections. This needs to be handled more generally where AudioNodes have
463         // a tailTime attribute. Then the AudioNode only needs to remain "active" for tailTime seconds after there are no
464         // longer any active connections.
465         if (nodeType() != NodeTypeConvolver && nodeType() != NodeTypeDelay) {
466             m_isDisabled = true;
467             for (unsigned i = 0; i < m_outputs.size(); ++i)
468                 output(i)->disable();
469         }
470     }
471 }
472
473 void AudioNode::ref(RefType refType)
474 {
475     switch (refType) {
476     case RefTypeNormal:
477         atomicIncrement(&m_normalRefCount);
478         break;
479     case RefTypeConnection:
480         atomicIncrement(&m_connectionRefCount);
481         break;
482     default:
483         ASSERT_NOT_REACHED();
484     }
485
486 #if DEBUG_AUDIONODE_REFERENCES
487     fprintf(stderr, "%p: %d: AudioNode::ref(%d) %d %d\n", this, nodeType(), refType, m_normalRefCount, m_connectionRefCount);
488 #endif
489
490     // See the disabling code in finishDeref() below. This handles the case where a node
491     // is being re-connected after being used at least once and disconnected.
492     // In this case, we need to re-enable.
493     if (refType == RefTypeConnection)
494         enableOutputsIfNecessary();
495 }
496
497 void AudioNode::deref(RefType refType)
498 {
499     // The actually work for deref happens completely within the audio context's graph lock.
500     // In the case of the audio thread, we must use a tryLock to avoid glitches.
501     bool hasLock = false;
502     bool mustReleaseLock = false;
503
504     if (context()->isAudioThread()) {
505         // Real-time audio thread must not contend lock (to avoid glitches).
506         hasLock = context()->tryLock(mustReleaseLock);
507     } else {
508         context()->lock(mustReleaseLock);
509         hasLock = true;
510     }
511
512     if (hasLock) {
513         // This is where the real deref work happens.
514         finishDeref(refType);
515
516         if (mustReleaseLock)
517             context()->unlock();
518     } else {
519         // We were unable to get the lock, so put this in a list to finish up later.
520         ASSERT(context()->isAudioThread());
521         ASSERT(refType == RefTypeConnection);
522         context()->addDeferredFinishDeref(this);
523     }
524
525     // Once AudioContext::uninitialize() is called there's no more chances for deleteMarkedNodes() to get called, so we call here.
526     // We can't call in AudioContext::~AudioContext() since it will never be called as long as any AudioNode is alive
527     // because AudioNodes keep a reference to the context.
528     if (context()->isAudioThreadFinished())
529         context()->deleteMarkedNodes();
530 }
531
532 void AudioNode::finishDeref(RefType refType)
533 {
534     ASSERT(context()->isGraphOwner());
535
536     switch (refType) {
537     case RefTypeNormal:
538         ASSERT(m_normalRefCount > 0);
539         atomicDecrement(&m_normalRefCount);
540         break;
541     case RefTypeConnection:
542         ASSERT(m_connectionRefCount > 0);
543         atomicDecrement(&m_connectionRefCount);
544         break;
545     default:
546         ASSERT_NOT_REACHED();
547     }
548
549 #if DEBUG_AUDIONODE_REFERENCES
550     fprintf(stderr, "%p: %d: AudioNode::deref(%d) %d %d\n", this, nodeType(), refType, m_normalRefCount, m_connectionRefCount);
551 #endif
552
553     if (!m_connectionRefCount) {
554         if (!m_normalRefCount) {
555             if (!m_isMarkedForDeletion) {
556                 // All references are gone - we need to go away.
557                 for (unsigned i = 0; i < m_outputs.size(); ++i)
558                     output(i)->disconnectAll(); // This will deref() nodes we're connected to.
559
560                 // Mark for deletion at end of each render quantum or when context shuts down.
561                 context()->markForDeletion(this);
562                 m_isMarkedForDeletion = true;
563             }
564         } else if (refType == RefTypeConnection)
565             disableOutputsIfNecessary();
566     }
567 }
568
569 #if DEBUG_AUDIONODE_REFERENCES
570
571 bool AudioNode::s_isNodeCountInitialized = false;
572 int AudioNode::s_nodeCount[NodeTypeEnd];
573
574 void AudioNode::printNodeCounts()
575 {
576     fprintf(stderr, "\n\n");
577     fprintf(stderr, "===========================\n");
578     fprintf(stderr, "AudioNode: reference counts\n");
579     fprintf(stderr, "===========================\n");
580
581     for (unsigned i = 0; i < NodeTypeEnd; ++i)
582         fprintf(stderr, "%d: %d\n", i, s_nodeCount[i]);
583
584     fprintf(stderr, "===========================\n\n\n");
585 }
586
587 #endif // DEBUG_AUDIONODE_REFERENCES
588
589 } // namespace WebCore
590
591 #endif // ENABLE(WEB_AUDIO)