Line data Source code
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 "nsTArray.h"
14 : #include "AudioContext.h"
15 : #include "MediaStreamGraph.h"
16 : #include "WebAudioUtils.h"
17 : #include "mozilla/MemoryReporting.h"
18 : #include "nsWeakReference.h"
19 : #include "SelfRef.h"
20 :
21 : namespace mozilla {
22 :
23 : class AbstractThread;
24 :
25 : namespace dom {
26 :
27 : class AudioContext;
28 : class AudioBufferSourceNode;
29 : class AudioParam;
30 : class AudioParamTimeline;
31 : struct ThreeDPoint;
32 :
33 : /**
34 : * The DOM object representing a Web Audio AudioNode.
35 : *
36 : * Each AudioNode has a MediaStream representing the actual
37 : * real-time processing and output of this AudioNode.
38 : *
39 : * We track the incoming and outgoing connections to other AudioNodes.
40 : * Outgoing connections have strong ownership. Also, AudioNodes that will
41 : * produce sound on their output even when they have silent or no input ask
42 : * the AudioContext to keep playing or tail-time references to keep them alive
43 : * until the context is finished.
44 : *
45 : * Explicit disconnections will only remove references from output nodes after
46 : * the graph is notified and the main thread receives a reply. Similarly,
47 : * nodes with playing or tail-time references release these references only
48 : * after receiving notification from their engine on the graph thread that
49 : * playing has stopped. Engines notifying the main thread that they have
50 : * finished do so strictly *after* producing and returning their last block.
51 : * In this way, an engine that receives non-null input knows that the input
52 : * comes from nodes that are still alive and will keep their output nodes
53 : * alive for at least as long as it takes to process messages from the graph
54 : * thread. i.e. the engine receiving non-null input knows that its node is
55 : * still alive, and will still be alive when it receives a message from the
56 : * engine.
57 : */
58 : class AudioNode : public DOMEventTargetHelper,
59 : public nsSupportsWeakReference
60 : {
61 : protected:
62 : // You can only use refcounting to delete this object
63 : virtual ~AudioNode();
64 :
65 : public:
66 : AudioNode(AudioContext* aContext,
67 : uint32_t aChannelCount,
68 : ChannelCountMode aChannelCountMode,
69 : ChannelInterpretation aChannelInterpretation);
70 :
71 : // This should be idempotent (safe to call multiple times).
72 : virtual void DestroyMediaStream();
73 :
74 : NS_DECL_ISUPPORTS_INHERITED
75 0 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioNode,
76 : DOMEventTargetHelper)
77 :
78 0 : virtual AudioBufferSourceNode* AsAudioBufferSourceNode()
79 : {
80 0 : return nullptr;
81 : }
82 :
83 0 : AudioContext* GetParentObject() const
84 : {
85 0 : return mContext;
86 : }
87 :
88 0 : AudioContext* Context() const
89 : {
90 0 : return mContext;
91 : }
92 :
93 : virtual AudioNode* Connect(AudioNode& aDestination, uint32_t aOutput,
94 : uint32_t aInput, ErrorResult& aRv);
95 :
96 : virtual void Connect(AudioParam& aDestination, uint32_t aOutput,
97 : ErrorResult& aRv);
98 :
99 : virtual void Disconnect(ErrorResult& aRv);
100 : virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv);
101 : virtual void Disconnect(AudioNode& aDestination, ErrorResult& aRv);
102 : virtual void Disconnect(AudioNode& aDestination, uint32_t aOutput,
103 : ErrorResult& aRv);
104 : virtual void Disconnect(AudioNode& aDestination,
105 : uint32_t aOutput, uint32_t aInput,
106 : ErrorResult& aRv);
107 : virtual void Disconnect(AudioParam& aDestination, ErrorResult& aRv);
108 : virtual void Disconnect(AudioParam& aDestination, uint32_t aOutput,
109 : ErrorResult& aRv);
110 :
111 : // Called after input nodes have been explicitly added or removed through
112 : // the Connect() or Disconnect() methods.
113 0 : virtual void NotifyInputsChanged() {}
114 : // Indicate that the node should continue indefinitely to behave as if an
115 : // input is connected, even though there is no longer a corresponding entry
116 : // in mInputNodes. Called after an input node has been removed because it
117 : // is being garbage collected.
118 0 : virtual void NotifyHasPhantomInput() {}
119 :
120 : // The following two virtual methods must be implemented by each node type
121 : // to provide their number of input and output ports. These numbers are
122 : // constant for the lifetime of the node. Both default to 1.
123 0 : virtual uint16_t NumberOfInputs() const { return 1; }
124 0 : virtual uint16_t NumberOfOutputs() const { return 1; }
125 :
126 0 : uint32_t Id() const { return mId; }
127 :
128 : bool PassThrough() const;
129 : void SetPassThrough(bool aPassThrough);
130 :
131 0 : uint32_t ChannelCount() const { return mChannelCount; }
132 0 : virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
133 : {
134 0 : if (aChannelCount == 0 ||
135 : aChannelCount > WebAudioUtils::MaxChannelCount) {
136 0 : aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
137 0 : return;
138 : }
139 0 : mChannelCount = aChannelCount;
140 0 : SendChannelMixingParametersToStream();
141 : }
142 0 : ChannelCountMode ChannelCountModeValue() const
143 : {
144 0 : return mChannelCountMode;
145 : }
146 0 : virtual void SetChannelCountModeValue(ChannelCountMode aMode, ErrorResult& aRv)
147 : {
148 0 : mChannelCountMode = aMode;
149 0 : SendChannelMixingParametersToStream();
150 0 : }
151 0 : ChannelInterpretation ChannelInterpretationValue() const
152 : {
153 0 : return mChannelInterpretation;
154 : }
155 0 : void SetChannelInterpretationValue(ChannelInterpretation aMode)
156 : {
157 0 : mChannelInterpretation = aMode;
158 0 : SendChannelMixingParametersToStream();
159 0 : }
160 :
161 0 : struct InputNode final
162 : {
163 0 : ~InputNode()
164 0 : {
165 0 : if (mStreamPort) {
166 0 : mStreamPort->Destroy();
167 : }
168 0 : }
169 :
170 0 : size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
171 : {
172 0 : size_t amount = 0;
173 0 : if (mStreamPort) {
174 0 : amount += mStreamPort->SizeOfIncludingThis(aMallocSizeOf);
175 : }
176 :
177 0 : return amount;
178 : }
179 :
180 : // Weak reference.
181 : AudioNode* mInputNode;
182 : RefPtr<MediaInputPort> mStreamPort;
183 : // The index of the input port this node feeds into.
184 : // This is not used for connections to AudioParams.
185 : uint32_t mInputPort;
186 : // The index of the output port this node comes out of.
187 : uint32_t mOutputPort;
188 : };
189 :
190 : // Returns the stream, if any.
191 0 : AudioNodeStream* GetStream() const { return mStream; }
192 :
193 0 : const nsTArray<InputNode>& InputNodes() const
194 : {
195 0 : return mInputNodes;
196 : }
197 0 : const nsTArray<RefPtr<AudioNode> >& OutputNodes() const
198 : {
199 0 : return mOutputNodes;
200 : }
201 0 : const nsTArray<RefPtr<AudioParam> >& OutputParams() const
202 : {
203 0 : return mOutputParams;
204 : }
205 :
206 : template<typename T>
207 : const nsTArray<InputNode>&
208 : InputsForDestination(uint32_t aOutputIndex) const;
209 :
210 : void RemoveOutputParam(AudioParam* aParam);
211 :
212 : // MarkActive() asks the context to keep the AudioNode alive until the
213 : // context is finished. This takes care of "playing" references and
214 : // "tail-time" references.
215 0 : void MarkActive() { Context()->RegisterActiveNode(this); }
216 : // Active nodes call MarkInactive() when they have finished producing sound
217 : // for the foreseeable future.
218 : // Do not call MarkInactive from a node destructor. If the destructor is
219 : // called, then the node is already inactive.
220 : // MarkInactive() may delete |this|.
221 0 : void MarkInactive() { Context()->UnregisterActiveNode(this); }
222 :
223 : virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
224 : virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
225 :
226 : // Returns a string from constant static storage identifying the dom node
227 : // type.
228 : virtual const char* NodeType() const = 0;
229 :
230 0 : AbstractThread* AbstractMainThread() const { return mAbstractMainThread; }
231 :
232 : private:
233 : // Given:
234 : //
235 : // - a DestinationType, that can be an AudioNode or an AudioParam ;
236 : // - a Predicate, a function that takes an InputNode& and returns a bool ;
237 : //
238 : // This method iterates on the InputNodes() of the node at the index
239 : // aDestinationIndex, and calls `DisconnectFromOutputIfConnected` with this
240 : // input node, if aPredicate returns true.
241 : template<typename DestinationType, typename Predicate>
242 : bool DisconnectMatchingDestinationInputs(uint32_t aDestinationIndex,
243 : Predicate aPredicate);
244 :
245 0 : virtual void LastRelease() override
246 : {
247 : // We are about to be deleted, disconnect the object from the graph before
248 : // the derived type is destroyed.
249 0 : DisconnectFromGraph();
250 0 : }
251 : // Callers must hold a reference to 'this'.
252 : void DisconnectFromGraph();
253 :
254 : template<typename DestinationType>
255 : bool DisconnectFromOutputIfConnected(uint32_t aOutputIndex, uint32_t aInputIndex);
256 :
257 : protected:
258 : // Helper for the Constructors for nodes.
259 : void Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv);
260 :
261 : // Helpers for sending different value types to streams
262 : void SendDoubleParameterToStream(uint32_t aIndex, double aValue);
263 : void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue);
264 : void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue);
265 : void SendChannelMixingParametersToStream();
266 :
267 : private:
268 : RefPtr<AudioContext> mContext;
269 :
270 : protected:
271 : // Must be set in the constructor. Must not be null unless finished.
272 : RefPtr<AudioNodeStream> mStream;
273 :
274 : private:
275 : // For every InputNode, there is a corresponding entry in mOutputNodes of the
276 : // InputNode's mInputNode.
277 : nsTArray<InputNode> mInputNodes;
278 : // For every mOutputNode entry, there is a corresponding entry in mInputNodes
279 : // of the mOutputNode entry. We won't necessarily be able to identify the
280 : // exact matching entry, since mOutputNodes doesn't include the port
281 : // identifiers and the same node could be connected on multiple ports.
282 : nsTArray<RefPtr<AudioNode> > mOutputNodes;
283 : // For every mOutputParams entry, there is a corresponding entry in
284 : // AudioParam::mInputNodes of the mOutputParams entry. We won't necessarily be
285 : // able to identify the exact matching entry, since mOutputParams doesn't
286 : // include the port identifiers and the same node could be connected on
287 : // multiple ports.
288 : nsTArray<RefPtr<AudioParam> > mOutputParams;
289 : uint32_t mChannelCount;
290 : ChannelCountMode mChannelCountMode;
291 : ChannelInterpretation mChannelInterpretation;
292 : const uint32_t mId;
293 : // Whether the node just passes through its input. This is a devtools API that
294 : // only works for some node types.
295 : bool mPassThrough;
296 : // DocGroup-specifc AbstractThread::MainThread() for MediaStreamGraph operations.
297 : const RefPtr<AbstractThread> mAbstractMainThread;
298 : };
299 :
300 : } // namespace dom
301 : } // namespace mozilla
302 :
303 : #endif
|