|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef AudioNode_h_ |
|
8 #define AudioNode_h_ |
|
9 |
|
10 #include "mozilla/DOMEventTargetHelper.h" |
|
11 #include "mozilla/dom/AudioNodeBinding.h" |
|
12 #include "nsCycleCollectionParticipant.h" |
|
13 #include "nsAutoPtr.h" |
|
14 #include "nsTArray.h" |
|
15 #include "AudioContext.h" |
|
16 #include "MediaStreamGraph.h" |
|
17 #include "WebAudioUtils.h" |
|
18 #include "mozilla/MemoryReporting.h" |
|
19 |
|
20 namespace mozilla { |
|
21 |
|
22 namespace dom { |
|
23 |
|
24 class AudioContext; |
|
25 class AudioBufferSourceNode; |
|
26 class AudioParam; |
|
27 class AudioParamTimeline; |
|
28 struct ThreeDPoint; |
|
29 |
|
30 template<class T> |
|
31 class SelfReference { |
|
32 public: |
|
33 SelfReference() : mHeld(false) {} |
|
34 ~SelfReference() |
|
35 { |
|
36 NS_ASSERTION(!mHeld, "Forgot to drop the self reference?"); |
|
37 } |
|
38 |
|
39 void Take(T* t) |
|
40 { |
|
41 if (!mHeld) { |
|
42 mHeld = true; |
|
43 t->AddRef(); |
|
44 } |
|
45 } |
|
46 void Drop(T* t) |
|
47 { |
|
48 if (mHeld) { |
|
49 mHeld = false; |
|
50 t->Release(); |
|
51 } |
|
52 } |
|
53 |
|
54 operator bool() const { return mHeld; } |
|
55 |
|
56 private: |
|
57 bool mHeld; |
|
58 }; |
|
59 |
|
60 /** |
|
61 * The DOM object representing a Web Audio AudioNode. |
|
62 * |
|
63 * Each AudioNode has a MediaStream representing the actual |
|
64 * real-time processing and output of this AudioNode. |
|
65 * |
|
66 * We track the incoming and outgoing connections to other AudioNodes. |
|
67 * Outgoing connections have strong ownership. Also, AudioNodes that will |
|
68 * produce sound on their output even when they have silent or no input ask |
|
69 * the AudioContext to keep playing or tail-time references to keep them alive |
|
70 * until the context is finished. |
|
71 * |
|
72 * Explicit disconnections will only remove references from output nodes after |
|
73 * the graph is notified and the main thread receives a reply. Similarly, |
|
74 * nodes with playing or tail-time references release these references only |
|
75 * after receiving notification from their engine on the graph thread that |
|
76 * playing has stopped. Engines notifying the main thread that they have |
|
77 * finished do so strictly *after* producing and returning their last block. |
|
78 * In this way, an engine that receives non-null input knows that the input |
|
79 * comes from nodes that are still alive and will keep their output nodes |
|
80 * alive for at least as long as it takes to process messages from the graph |
|
81 * thread. i.e. the engine receiving non-null input knows that its node is |
|
82 * still alive, and will still be alive when it receives a message from the |
|
83 * engine. |
|
84 */ |
|
85 class AudioNode : public DOMEventTargetHelper |
|
86 { |
|
87 protected: |
|
88 // You can only use refcounting to delete this object |
|
89 virtual ~AudioNode(); |
|
90 |
|
91 public: |
|
92 AudioNode(AudioContext* aContext, |
|
93 uint32_t aChannelCount, |
|
94 ChannelCountMode aChannelCountMode, |
|
95 ChannelInterpretation aChannelInterpretation); |
|
96 |
|
97 // This should be idempotent (safe to call multiple times). |
|
98 virtual void DestroyMediaStream(); |
|
99 |
|
100 NS_DECL_ISUPPORTS_INHERITED |
|
101 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioNode, |
|
102 DOMEventTargetHelper) |
|
103 |
|
104 virtual AudioBufferSourceNode* AsAudioBufferSourceNode() { |
|
105 return nullptr; |
|
106 } |
|
107 |
|
108 virtual const DelayNode* AsDelayNode() const { |
|
109 return nullptr; |
|
110 } |
|
111 |
|
112 AudioContext* GetParentObject() const |
|
113 { |
|
114 return mContext; |
|
115 } |
|
116 |
|
117 AudioContext* Context() const |
|
118 { |
|
119 return mContext; |
|
120 } |
|
121 |
|
122 virtual void Connect(AudioNode& aDestination, uint32_t aOutput, |
|
123 uint32_t aInput, ErrorResult& aRv); |
|
124 |
|
125 virtual void Connect(AudioParam& aDestination, uint32_t aOutput, |
|
126 ErrorResult& aRv); |
|
127 |
|
128 virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv); |
|
129 |
|
130 // The following two virtual methods must be implemented by each node type |
|
131 // to provide their number of input and output ports. These numbers are |
|
132 // constant for the lifetime of the node. Both default to 1. |
|
133 virtual uint16_t NumberOfInputs() const { return 1; } |
|
134 virtual uint16_t NumberOfOutputs() const { return 1; } |
|
135 |
|
136 uint32_t ChannelCount() const { return mChannelCount; } |
|
137 virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) |
|
138 { |
|
139 if (aChannelCount == 0 || |
|
140 aChannelCount > WebAudioUtils::MaxChannelCount) { |
|
141 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
|
142 return; |
|
143 } |
|
144 mChannelCount = aChannelCount; |
|
145 SendChannelMixingParametersToStream(); |
|
146 } |
|
147 ChannelCountMode ChannelCountModeValue() const |
|
148 { |
|
149 return mChannelCountMode; |
|
150 } |
|
151 virtual void SetChannelCountModeValue(ChannelCountMode aMode, ErrorResult& aRv) |
|
152 { |
|
153 mChannelCountMode = aMode; |
|
154 SendChannelMixingParametersToStream(); |
|
155 } |
|
156 ChannelInterpretation ChannelInterpretationValue() const |
|
157 { |
|
158 return mChannelInterpretation; |
|
159 } |
|
160 void SetChannelInterpretationValue(ChannelInterpretation aMode) |
|
161 { |
|
162 mChannelInterpretation = aMode; |
|
163 SendChannelMixingParametersToStream(); |
|
164 } |
|
165 |
|
166 struct InputNode { |
|
167 ~InputNode() |
|
168 { |
|
169 if (mStreamPort) { |
|
170 mStreamPort->Destroy(); |
|
171 } |
|
172 } |
|
173 |
|
174 size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
|
175 { |
|
176 size_t amount = 0; |
|
177 if (mStreamPort) { |
|
178 amount += mStreamPort->SizeOfIncludingThis(aMallocSizeOf); |
|
179 } |
|
180 |
|
181 return amount; |
|
182 } |
|
183 |
|
184 // Weak reference. |
|
185 AudioNode* mInputNode; |
|
186 nsRefPtr<MediaInputPort> mStreamPort; |
|
187 // The index of the input port this node feeds into. |
|
188 // This is not used for connections to AudioParams. |
|
189 uint32_t mInputPort; |
|
190 // The index of the output port this node comes out of. |
|
191 uint32_t mOutputPort; |
|
192 }; |
|
193 |
|
194 MediaStream* Stream() { return mStream; } |
|
195 |
|
196 const nsTArray<InputNode>& InputNodes() const |
|
197 { |
|
198 return mInputNodes; |
|
199 } |
|
200 const nsTArray<nsRefPtr<AudioNode> >& OutputNodes() const |
|
201 { |
|
202 return mOutputNodes; |
|
203 } |
|
204 const nsTArray<nsRefPtr<AudioParam> >& OutputParams() const |
|
205 { |
|
206 return mOutputParams; |
|
207 } |
|
208 |
|
209 void RemoveOutputParam(AudioParam* aParam); |
|
210 |
|
211 // MarkActive() asks the context to keep the AudioNode alive until the |
|
212 // context is finished. This takes care of "playing" references and |
|
213 // "tail-time" references. |
|
214 void MarkActive() { Context()->RegisterActiveNode(this); } |
|
215 // Active nodes call MarkInactive() when they have finished producing sound |
|
216 // for the foreseeable future. |
|
217 // Do not call MarkInactive from a node destructor. If the destructor is |
|
218 // called, then the node is already inactive. |
|
219 // MarkInactive() may delete |this|. |
|
220 void MarkInactive() { Context()->UnregisterActiveNode(this); } |
|
221 |
|
222 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; |
|
223 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
|
224 |
|
225 virtual const char* NodeType() const = 0; |
|
226 |
|
227 private: |
|
228 friend class AudioBufferSourceNode; |
|
229 // This could possibly delete 'this'. |
|
230 void DisconnectFromGraph(); |
|
231 |
|
232 protected: |
|
233 static void Callback(AudioNode* aNode) { /* not implemented */ } |
|
234 |
|
235 // Helpers for sending different value types to streams |
|
236 void SendDoubleParameterToStream(uint32_t aIndex, double aValue); |
|
237 void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue); |
|
238 void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue); |
|
239 void SendChannelMixingParametersToStream(); |
|
240 static void SendTimelineParameterToStream(AudioNode* aNode, uint32_t aIndex, |
|
241 const AudioParamTimeline& aValue); |
|
242 |
|
243 private: |
|
244 nsRefPtr<AudioContext> mContext; |
|
245 |
|
246 protected: |
|
247 // Must be set in the constructor. Must not be null. |
|
248 // If MaxNumberOfInputs() is > 0, then mStream must be a ProcessedMediaStream. |
|
249 nsRefPtr<MediaStream> mStream; |
|
250 |
|
251 private: |
|
252 // For every InputNode, there is a corresponding entry in mOutputNodes of the |
|
253 // InputNode's mInputNode. |
|
254 nsTArray<InputNode> mInputNodes; |
|
255 // For every mOutputNode entry, there is a corresponding entry in mInputNodes |
|
256 // of the mOutputNode entry. We won't necessarily be able to identify the |
|
257 // exact matching entry, since mOutputNodes doesn't include the port |
|
258 // identifiers and the same node could be connected on multiple ports. |
|
259 nsTArray<nsRefPtr<AudioNode> > mOutputNodes; |
|
260 // For every mOutputParams entry, there is a corresponding entry in |
|
261 // AudioParam::mInputNodes of the mOutputParams entry. We won't necessarily be |
|
262 // able to identify the exact matching entry, since mOutputParams doesn't |
|
263 // include the port identifiers and the same node could be connected on |
|
264 // multiple ports. |
|
265 nsTArray<nsRefPtr<AudioParam> > mOutputParams; |
|
266 uint32_t mChannelCount; |
|
267 ChannelCountMode mChannelCountMode; |
|
268 ChannelInterpretation mChannelInterpretation; |
|
269 }; |
|
270 |
|
271 } |
|
272 } |
|
273 |
|
274 #endif |