1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/AudioNode.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,274 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef AudioNode_h_ 1.11 +#define AudioNode_h_ 1.12 + 1.13 +#include "mozilla/DOMEventTargetHelper.h" 1.14 +#include "mozilla/dom/AudioNodeBinding.h" 1.15 +#include "nsCycleCollectionParticipant.h" 1.16 +#include "nsAutoPtr.h" 1.17 +#include "nsTArray.h" 1.18 +#include "AudioContext.h" 1.19 +#include "MediaStreamGraph.h" 1.20 +#include "WebAudioUtils.h" 1.21 +#include "mozilla/MemoryReporting.h" 1.22 + 1.23 +namespace mozilla { 1.24 + 1.25 +namespace dom { 1.26 + 1.27 +class AudioContext; 1.28 +class AudioBufferSourceNode; 1.29 +class AudioParam; 1.30 +class AudioParamTimeline; 1.31 +struct ThreeDPoint; 1.32 + 1.33 +template<class T> 1.34 +class SelfReference { 1.35 +public: 1.36 + SelfReference() : mHeld(false) {} 1.37 + ~SelfReference() 1.38 + { 1.39 + NS_ASSERTION(!mHeld, "Forgot to drop the self reference?"); 1.40 + } 1.41 + 1.42 + void Take(T* t) 1.43 + { 1.44 + if (!mHeld) { 1.45 + mHeld = true; 1.46 + t->AddRef(); 1.47 + } 1.48 + } 1.49 + void Drop(T* t) 1.50 + { 1.51 + if (mHeld) { 1.52 + mHeld = false; 1.53 + t->Release(); 1.54 + } 1.55 + } 1.56 + 1.57 + operator bool() const { return mHeld; } 1.58 + 1.59 +private: 1.60 + bool mHeld; 1.61 +}; 1.62 + 1.63 +/** 1.64 + * The DOM object representing a Web Audio AudioNode. 1.65 + * 1.66 + * Each AudioNode has a MediaStream representing the actual 1.67 + * real-time processing and output of this AudioNode. 1.68 + * 1.69 + * We track the incoming and outgoing connections to other AudioNodes. 1.70 + * Outgoing connections have strong ownership. Also, AudioNodes that will 1.71 + * produce sound on their output even when they have silent or no input ask 1.72 + * the AudioContext to keep playing or tail-time references to keep them alive 1.73 + * until the context is finished. 1.74 + * 1.75 + * Explicit disconnections will only remove references from output nodes after 1.76 + * the graph is notified and the main thread receives a reply. Similarly, 1.77 + * nodes with playing or tail-time references release these references only 1.78 + * after receiving notification from their engine on the graph thread that 1.79 + * playing has stopped. Engines notifying the main thread that they have 1.80 + * finished do so strictly *after* producing and returning their last block. 1.81 + * In this way, an engine that receives non-null input knows that the input 1.82 + * comes from nodes that are still alive and will keep their output nodes 1.83 + * alive for at least as long as it takes to process messages from the graph 1.84 + * thread. i.e. the engine receiving non-null input knows that its node is 1.85 + * still alive, and will still be alive when it receives a message from the 1.86 + * engine. 1.87 + */ 1.88 +class AudioNode : public DOMEventTargetHelper 1.89 +{ 1.90 +protected: 1.91 + // You can only use refcounting to delete this object 1.92 + virtual ~AudioNode(); 1.93 + 1.94 +public: 1.95 + AudioNode(AudioContext* aContext, 1.96 + uint32_t aChannelCount, 1.97 + ChannelCountMode aChannelCountMode, 1.98 + ChannelInterpretation aChannelInterpretation); 1.99 + 1.100 + // This should be idempotent (safe to call multiple times). 1.101 + virtual void DestroyMediaStream(); 1.102 + 1.103 + NS_DECL_ISUPPORTS_INHERITED 1.104 + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioNode, 1.105 + DOMEventTargetHelper) 1.106 + 1.107 + virtual AudioBufferSourceNode* AsAudioBufferSourceNode() { 1.108 + return nullptr; 1.109 + } 1.110 + 1.111 + virtual const DelayNode* AsDelayNode() const { 1.112 + return nullptr; 1.113 + } 1.114 + 1.115 + AudioContext* GetParentObject() const 1.116 + { 1.117 + return mContext; 1.118 + } 1.119 + 1.120 + AudioContext* Context() const 1.121 + { 1.122 + return mContext; 1.123 + } 1.124 + 1.125 + virtual void Connect(AudioNode& aDestination, uint32_t aOutput, 1.126 + uint32_t aInput, ErrorResult& aRv); 1.127 + 1.128 + virtual void Connect(AudioParam& aDestination, uint32_t aOutput, 1.129 + ErrorResult& aRv); 1.130 + 1.131 + virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv); 1.132 + 1.133 + // The following two virtual methods must be implemented by each node type 1.134 + // to provide their number of input and output ports. These numbers are 1.135 + // constant for the lifetime of the node. Both default to 1. 1.136 + virtual uint16_t NumberOfInputs() const { return 1; } 1.137 + virtual uint16_t NumberOfOutputs() const { return 1; } 1.138 + 1.139 + uint32_t ChannelCount() const { return mChannelCount; } 1.140 + virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) 1.141 + { 1.142 + if (aChannelCount == 0 || 1.143 + aChannelCount > WebAudioUtils::MaxChannelCount) { 1.144 + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.145 + return; 1.146 + } 1.147 + mChannelCount = aChannelCount; 1.148 + SendChannelMixingParametersToStream(); 1.149 + } 1.150 + ChannelCountMode ChannelCountModeValue() const 1.151 + { 1.152 + return mChannelCountMode; 1.153 + } 1.154 + virtual void SetChannelCountModeValue(ChannelCountMode aMode, ErrorResult& aRv) 1.155 + { 1.156 + mChannelCountMode = aMode; 1.157 + SendChannelMixingParametersToStream(); 1.158 + } 1.159 + ChannelInterpretation ChannelInterpretationValue() const 1.160 + { 1.161 + return mChannelInterpretation; 1.162 + } 1.163 + void SetChannelInterpretationValue(ChannelInterpretation aMode) 1.164 + { 1.165 + mChannelInterpretation = aMode; 1.166 + SendChannelMixingParametersToStream(); 1.167 + } 1.168 + 1.169 + struct InputNode { 1.170 + ~InputNode() 1.171 + { 1.172 + if (mStreamPort) { 1.173 + mStreamPort->Destroy(); 1.174 + } 1.175 + } 1.176 + 1.177 + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.178 + { 1.179 + size_t amount = 0; 1.180 + if (mStreamPort) { 1.181 + amount += mStreamPort->SizeOfIncludingThis(aMallocSizeOf); 1.182 + } 1.183 + 1.184 + return amount; 1.185 + } 1.186 + 1.187 + // Weak reference. 1.188 + AudioNode* mInputNode; 1.189 + nsRefPtr<MediaInputPort> mStreamPort; 1.190 + // The index of the input port this node feeds into. 1.191 + // This is not used for connections to AudioParams. 1.192 + uint32_t mInputPort; 1.193 + // The index of the output port this node comes out of. 1.194 + uint32_t mOutputPort; 1.195 + }; 1.196 + 1.197 + MediaStream* Stream() { return mStream; } 1.198 + 1.199 + const nsTArray<InputNode>& InputNodes() const 1.200 + { 1.201 + return mInputNodes; 1.202 + } 1.203 + const nsTArray<nsRefPtr<AudioNode> >& OutputNodes() const 1.204 + { 1.205 + return mOutputNodes; 1.206 + } 1.207 + const nsTArray<nsRefPtr<AudioParam> >& OutputParams() const 1.208 + { 1.209 + return mOutputParams; 1.210 + } 1.211 + 1.212 + void RemoveOutputParam(AudioParam* aParam); 1.213 + 1.214 + // MarkActive() asks the context to keep the AudioNode alive until the 1.215 + // context is finished. This takes care of "playing" references and 1.216 + // "tail-time" references. 1.217 + void MarkActive() { Context()->RegisterActiveNode(this); } 1.218 + // Active nodes call MarkInactive() when they have finished producing sound 1.219 + // for the foreseeable future. 1.220 + // Do not call MarkInactive from a node destructor. If the destructor is 1.221 + // called, then the node is already inactive. 1.222 + // MarkInactive() may delete |this|. 1.223 + void MarkInactive() { Context()->UnregisterActiveNode(this); } 1.224 + 1.225 + virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const; 1.226 + virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; 1.227 + 1.228 + virtual const char* NodeType() const = 0; 1.229 + 1.230 +private: 1.231 + friend class AudioBufferSourceNode; 1.232 + // This could possibly delete 'this'. 1.233 + void DisconnectFromGraph(); 1.234 + 1.235 +protected: 1.236 + static void Callback(AudioNode* aNode) { /* not implemented */ } 1.237 + 1.238 + // Helpers for sending different value types to streams 1.239 + void SendDoubleParameterToStream(uint32_t aIndex, double aValue); 1.240 + void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue); 1.241 + void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue); 1.242 + void SendChannelMixingParametersToStream(); 1.243 + static void SendTimelineParameterToStream(AudioNode* aNode, uint32_t aIndex, 1.244 + const AudioParamTimeline& aValue); 1.245 + 1.246 +private: 1.247 + nsRefPtr<AudioContext> mContext; 1.248 + 1.249 +protected: 1.250 + // Must be set in the constructor. Must not be null. 1.251 + // If MaxNumberOfInputs() is > 0, then mStream must be a ProcessedMediaStream. 1.252 + nsRefPtr<MediaStream> mStream; 1.253 + 1.254 +private: 1.255 + // For every InputNode, there is a corresponding entry in mOutputNodes of the 1.256 + // InputNode's mInputNode. 1.257 + nsTArray<InputNode> mInputNodes; 1.258 + // For every mOutputNode entry, there is a corresponding entry in mInputNodes 1.259 + // of the mOutputNode entry. We won't necessarily be able to identify the 1.260 + // exact matching entry, since mOutputNodes doesn't include the port 1.261 + // identifiers and the same node could be connected on multiple ports. 1.262 + nsTArray<nsRefPtr<AudioNode> > mOutputNodes; 1.263 + // For every mOutputParams entry, there is a corresponding entry in 1.264 + // AudioParam::mInputNodes of the mOutputParams entry. We won't necessarily be 1.265 + // able to identify the exact matching entry, since mOutputParams doesn't 1.266 + // include the port identifiers and the same node could be connected on 1.267 + // multiple ports. 1.268 + nsTArray<nsRefPtr<AudioParam> > mOutputParams; 1.269 + uint32_t mChannelCount; 1.270 + ChannelCountMode mChannelCountMode; 1.271 + ChannelInterpretation mChannelInterpretation; 1.272 +}; 1.273 + 1.274 +} 1.275 +} 1.276 + 1.277 +#endif