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