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