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#pragma once
26
27#include "AudioBus.h"
28#include "EventTarget.h"
29#include "ExceptionOr.h"
30#include <wtf/Forward.h>
31#include <wtf/LoggerHelper.h>
32
33#define DEBUG_AUDIONODE_REFERENCES 0
34
35namespace WebCore {
36
37class AudioContext;
38class AudioNodeInput;
39class AudioNodeOutput;
40class AudioParam;
41
42// An AudioNode is the basic building block for handling audio within an AudioContext.
43// It may be an audio source, an intermediate processing module, or an audio destination.
44// Each AudioNode can have inputs and/or outputs. An AudioSourceNode has no inputs and a single output.
45// An AudioDestinationNode has one input and no outputs and represents the final destination to the audio hardware.
46// Most processing nodes such as filters will have one input and one output, although multiple inputs and outputs are possible.
47
48class AudioNode
49 : public EventTargetWithInlineData
50#if !RELEASE_LOG_DISABLED
51 , private LoggerHelper
52#endif
53{
54 WTF_MAKE_NONCOPYABLE(AudioNode);
55 WTF_MAKE_ISO_ALLOCATED(AudioNode);
56public:
57 enum { ProcessingSizeInFrames = 128 };
58
59 AudioNode(AudioContext&, float sampleRate);
60 virtual ~AudioNode();
61
62 AudioContext& context() { return m_context.get(); }
63 const AudioContext& context() const { return m_context.get(); }
64
65 enum NodeType {
66 NodeTypeUnknown,
67 NodeTypeDestination,
68 NodeTypeOscillator,
69 NodeTypeAudioBufferSource,
70 NodeTypeMediaElementAudioSource,
71 NodeTypeMediaStreamAudioDestination,
72 NodeTypeMediaStreamAudioSource,
73 NodeTypeJavaScript,
74 NodeTypeBiquadFilter,
75 NodeTypePanner,
76 NodeTypeConvolver,
77 NodeTypeDelay,
78 NodeTypeGain,
79 NodeTypeChannelSplitter,
80 NodeTypeChannelMerger,
81 NodeTypeAnalyser,
82 NodeTypeDynamicsCompressor,
83 NodeTypeWaveShaper,
84 NodeTypeBasicInspector,
85 NodeTypeEnd
86 };
87
88 enum ChannelCountMode {
89 Max,
90 ClampedMax,
91 Explicit
92 };
93
94 NodeType nodeType() const { return m_nodeType; }
95 void setNodeType(NodeType);
96
97 // We handle our own ref-counting because of the threading issues and subtle nature of
98 // how AudioNodes can continue processing (playing one-shot sound) after there are no more
99 // JavaScript references to the object.
100 enum RefType { RefTypeNormal, RefTypeConnection };
101
102 // Can be called from main thread or context's audio thread.
103 void ref(RefType refType = RefTypeNormal);
104 void deref(RefType refType = RefTypeNormal);
105
106 // Can be called from main thread or context's audio thread. It must be called while the context's graph lock is held.
107 void finishDeref(RefType refType);
108
109 // The AudioNodeInput(s) (if any) will already have their input data available when process() is called.
110 // Subclasses will take this input data and put the results in the AudioBus(s) of its AudioNodeOutput(s) (if any).
111 // Called from context's audio thread.
112 virtual void process(size_t framesToProcess) = 0;
113
114 // Resets DSP processing state (clears delay lines, filter memory, etc.)
115 // Called from context's audio thread.
116 virtual void reset() = 0;
117
118 // No significant resources should be allocated until initialize() is called.
119 // Processing may not occur until a node is initialized.
120 virtual void initialize();
121 virtual void uninitialize();
122
123 bool isInitialized() const { return m_isInitialized; }
124 void lazyInitialize();
125
126 unsigned numberOfInputs() const { return m_inputs.size(); }
127 unsigned numberOfOutputs() const { return m_outputs.size(); }
128
129 AudioNodeInput* input(unsigned);
130 AudioNodeOutput* output(unsigned);
131
132 // Called from main thread by corresponding JavaScript methods.
133 virtual ExceptionOr<void> connect(AudioNode&, unsigned outputIndex, unsigned inputIndex);
134 ExceptionOr<void> connect(AudioParam&, unsigned outputIndex);
135 virtual ExceptionOr<void> disconnect(unsigned outputIndex);
136
137 virtual float sampleRate() const { return m_sampleRate; }
138
139 // processIfNecessary() is called by our output(s) when the rendering graph needs this AudioNode to process.
140 // This method ensures that the AudioNode will only process once per rendering time quantum even if it's called repeatedly.
141 // This handles the case of "fanout" where an output is connected to multiple AudioNode inputs.
142 // Called from context's audio thread.
143 void processIfNecessary(size_t framesToProcess);
144
145 // Called when a new connection has been made to one of our inputs or the connection number of channels has changed.
146 // This potentially gives us enough information to perform a lazy initialization or, if necessary, a re-initialization.
147 // Called from main thread.
148 virtual void checkNumberOfChannelsForInput(AudioNodeInput*);
149
150#if DEBUG_AUDIONODE_REFERENCES
151 static void printNodeCounts();
152#endif
153
154 bool isMarkedForDeletion() const { return m_isMarkedForDeletion; }
155
156 // tailTime() is the length of time (not counting latency time) where non-zero output may occur after continuous silent input.
157 virtual double tailTime() const = 0;
158 // latencyTime() is the length of time it takes for non-zero output to appear after non-zero input is provided. This only applies to
159 // processing delay which is an artifact of the processing algorithm chosen and is *not* part of the intrinsic desired effect. For
160 // example, a "delay" effect is expected to delay the signal, and thus would not be considered latency.
161 virtual double latencyTime() const = 0;
162
163 // propagatesSilence() should return true if the node will generate silent output when given silent input. By default, AudioNode
164 // will take tailTime() and latencyTime() into account when determining whether the node will propagate silence.
165 virtual bool propagatesSilence() const;
166 bool inputsAreSilent();
167 void silenceOutputs();
168
169 void enableOutputsIfNecessary();
170 void disableOutputsIfNecessary();
171
172 unsigned channelCount();
173 virtual ExceptionOr<void> setChannelCount(unsigned);
174
175 String channelCountMode();
176 ExceptionOr<void> setChannelCountMode(const String&);
177
178 String channelInterpretation();
179 ExceptionOr<void> setChannelInterpretation(const String&);
180
181 ChannelCountMode internalChannelCountMode() const { return m_channelCountMode; }
182 AudioBus::ChannelInterpretation internalChannelInterpretation() const { return m_channelInterpretation; }
183
184protected:
185 // Inputs and outputs must be created before the AudioNode is initialized.
186 void addInput(std::unique_ptr<AudioNodeInput>);
187 void addOutput(std::unique_ptr<AudioNodeOutput>);
188
189 // Called by processIfNecessary() to cause all parts of the rendering graph connected to us to process.
190 // Each rendering quantum, the audio data for each of the AudioNode's inputs will be available after this method is called.
191 // Called from context's audio thread.
192 virtual void pullInputs(size_t framesToProcess);
193
194 // Force all inputs to take any channel interpretation changes into account.
195 void updateChannelsForInputs();
196
197#if !RELEASE_LOG_DISABLED
198 const Logger& logger() const final { return m_logger.get(); }
199 const void* logIdentifier() const final { return m_logIdentifier; }
200 const char* logClassName() const final { return "AudioNode"; }
201 WTFLogChannel& logChannel() const final;
202#endif
203
204private:
205 // EventTarget
206 EventTargetInterface eventTargetInterface() const override;
207 ScriptExecutionContext* scriptExecutionContext() const final;
208
209 volatile bool m_isInitialized;
210 NodeType m_nodeType;
211 Ref<AudioContext> m_context;
212 float m_sampleRate;
213 Vector<std::unique_ptr<AudioNodeInput>> m_inputs;
214 Vector<std::unique_ptr<AudioNodeOutput>> m_outputs;
215
216 double m_lastProcessingTime;
217 double m_lastNonSilentTime;
218
219 // Ref-counting
220 std::atomic<int> m_normalRefCount;
221 std::atomic<int> m_connectionRefCount;
222
223 bool m_isMarkedForDeletion;
224 bool m_isDisabled;
225
226#if DEBUG_AUDIONODE_REFERENCES
227 static bool s_isNodeCountInitialized;
228 static int s_nodeCount[NodeTypeEnd];
229#endif
230
231 void refEventTarget() override { ref(); }
232 void derefEventTarget() override { deref(); }
233
234#if !RELEASE_LOG_DISABLED
235 mutable Ref<const Logger> m_logger;
236 const void* m_logIdentifier;
237#endif
238
239protected:
240 unsigned m_channelCount;
241 ChannelCountMode m_channelCountMode;
242 AudioBus::ChannelInterpretation m_channelInterpretation;
243};
244
245String convertEnumerationToString(AudioNode::NodeType);
246
247} // namespace WebCore
248
249namespace WTF {
250
251template<> struct LogArgument<WebCore::AudioNode::NodeType> {
252 static String toString(WebCore::AudioNode::NodeType type) { return convertEnumerationToString(type); }
253};
254
255} // namespace WTF
256