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
44namespace blink {
45
46unsigned AudioNode::s_instanceCount = 0;
47
48AudioNode::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
72AudioNode::~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
82void AudioNode::initialize()
83{
84    m_isInitialized = true;
85}
86
87void AudioNode::uninitialize()
88{
89    m_isInitialized = false;
90}
91
92void 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
104String 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
149void 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
159void AudioNode::addInput()
160{
161    m_inputs.append(AudioNodeInput::create(*this));
162}
163
164void AudioNode::addOutput(AudioNodeOutput* output)
165{
166    m_outputs.append(output);
167}
168
169AudioNodeInput* AudioNode::input(unsigned i)
170{
171    if (i < m_inputs.size())
172        return m_inputs[i].get();
173    return 0;
174}
175
176AudioNodeOutput* AudioNode::output(unsigned i)
177{
178    if (i < m_outputs.size())
179        return m_outputs[i].get();
180    return 0;
181}
182
183void 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
224void 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
253void 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
270unsigned long AudioNode::channelCount()
271{
272    return m_channelCount;
273}
274
275void 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
293String 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
307void 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
328String 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
340void 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
354void AudioNode::updateChannelsForInputs()
355{
356    for (unsigned i = 0; i < m_inputs.size(); ++i)
357        input(i)->changedOutputs();
358}
359
360const AtomicString& AudioNode::interfaceName() const
361{
362    return EventTargetNames::AudioNode;
363}
364
365ExecutionContext* AudioNode::executionContext() const
366{
367    return const_cast<AudioNode*>(this)->context()->executionContext();
368}
369
370void 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
400void 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
411bool AudioNode::propagatesSilence() const
412{
413    return m_lastNonSilentTime + latencyTime() + tailTime() < context()->currentTime();
414}
415
416void 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
425bool 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
434void AudioNode::silenceOutputs()
435{
436    for (unsigned i = 0; i < m_outputs.size(); ++i)
437        output(i)->bus()->zero();
438}
439
440void AudioNode::unsilenceOutputs()
441{
442    for (unsigned i = 0; i < m_outputs.size(); ++i)
443        output(i)->bus()->clearSilentFlag();
444}
445
446void 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
458void 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
484void 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
498void 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
527void 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
542bool AudioNode::s_isNodeCountInitialized = false;
543int AudioNode::s_nodeCount[NodeTypeEnd];
544
545void 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
560void 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
568void AudioNode::updateChannelCountMode()
569{
570    m_channelCountMode = m_newChannelCountMode;
571    updateChannelsForInputs();
572}
573
574} // namespace blink
575
576#endif // ENABLE(WEB_AUDIO)
577