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