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 | |
35 | namespace WebCore { |
36 | |
37 | class AudioContext; |
38 | class AudioNodeInput; |
39 | class AudioNodeOutput; |
40 | class 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 | |
48 | class 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); |
56 | public: |
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 | |
184 | protected: |
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 | |
204 | private: |
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 | |
239 | protected: |
240 | unsigned m_channelCount; |
241 | ChannelCountMode m_channelCountMode; |
242 | AudioBus::ChannelInterpretation m_channelInterpretation; |
243 | }; |
244 | |
245 | String convertEnumerationToString(AudioNode::NodeType); |
246 | |
247 | } // namespace WebCore |
248 | |
249 | namespace WTF { |
250 | |
251 | template<> struct LogArgument<WebCore::AudioNode::NodeType> { |
252 | static String toString(WebCore::AudioNode::NodeType type) { return convertEnumerationToString(type); } |
253 | }; |
254 | |
255 | } // namespace WTF |
256 | |