1/* 2 * Copyright (C) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#ifndef AudioContext_h 26#define AudioContext_h 27 28#include "ActiveDOMObject.h" 29#include "AsyncAudioDecoder.h" 30#include "AudioBus.h" 31#include "AudioDestinationNode.h" 32#include "EventListener.h" 33#include "EventTarget.h" 34#include "MediaCanStartListener.h" 35#include <atomic> 36#include <wtf/HashSet.h> 37#include <wtf/MainThread.h> 38#include <wtf/PassRefPtr.h> 39#include <wtf/RefCounted.h> 40#include <wtf/RefPtr.h> 41#include <wtf/ThreadSafeRefCounted.h> 42#include <wtf/Threading.h> 43#include <wtf/Vector.h> 44#include <wtf/text/AtomicStringHash.h> 45 46namespace WebCore { 47 48class AudioBuffer; 49class AudioBufferCallback; 50class AudioBufferSourceNode; 51class MediaElementAudioSourceNode; 52class MediaStreamAudioDestinationNode; 53class MediaStreamAudioSourceNode; 54class HRTFDatabaseLoader; 55class HTMLMediaElement; 56class ChannelMergerNode; 57class ChannelSplitterNode; 58class GainNode; 59class PannerNode; 60class AudioListener; 61class AudioSummingJunction; 62class BiquadFilterNode; 63class DelayNode; 64class Document; 65class ConvolverNode; 66class DynamicsCompressorNode; 67class AnalyserNode; 68class WaveShaperNode; 69class ScriptProcessorNode; 70class OscillatorNode; 71class PeriodicWave; 72 73// AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it. 74// For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. 75 76class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted<AudioContext>, public EventTargetWithInlineData, public MediaCanStartListener { 77public: 78 // Create an AudioContext for rendering to the audio hardware. 79 static PassRefPtr<AudioContext> create(Document&, ExceptionCode&); 80 81 // Create an AudioContext for offline (non-realtime) rendering. 82 static PassRefPtr<AudioContext> createOfflineContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode&); 83 84 virtual ~AudioContext(); 85 86 bool isInitialized() const; 87 88 bool isOfflineContext() { return m_isOfflineContext; } 89 90 // Returns true when initialize() was called AND all asynchronous initialization has completed. 91 bool isRunnable() const; 92 93 HRTFDatabaseLoader* hrtfDatabaseLoader() const { return m_hrtfDatabaseLoader.get(); } 94 95 // Document notification 96 virtual void stop() override; 97 98 Document* document() const; // ASSERTs if document no longer exists. 99 100 AudioDestinationNode* destination() { return m_destinationNode.get(); } 101 size_t currentSampleFrame() const { return m_destinationNode->currentSampleFrame(); } 102 double currentTime() const { return m_destinationNode->currentTime(); } 103 float sampleRate() const { return m_destinationNode->sampleRate(); } 104 unsigned long activeSourceCount() const { return static_cast<unsigned long>(m_activeSourceCount); } 105 106 void incrementActiveSourceCount(); 107 void decrementActiveSourceCount(); 108 109 PassRefPtr<AudioBuffer> createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode&); 110 PassRefPtr<AudioBuffer> createBuffer(ArrayBuffer*, bool mixToMono, ExceptionCode&); 111 112 // Asynchronous audio file data decoding. 113 void decodeAudioData(ArrayBuffer*, PassRefPtr<AudioBufferCallback>, PassRefPtr<AudioBufferCallback>, ExceptionCode& ec); 114 115 AudioListener* listener() { return m_listener.get(); } 116 117 // The AudioNode create methods are called on the main thread (from JavaScript). 118 PassRefPtr<AudioBufferSourceNode> createBufferSource(); 119#if ENABLE(VIDEO) 120 PassRefPtr<MediaElementAudioSourceNode> createMediaElementSource(HTMLMediaElement*, ExceptionCode&); 121#endif 122#if ENABLE(MEDIA_STREAM) 123 PassRefPtr<MediaStreamAudioSourceNode> createMediaStreamSource(MediaStream*, ExceptionCode&); 124 PassRefPtr<MediaStreamAudioDestinationNode> createMediaStreamDestination(); 125#endif 126 PassRefPtr<GainNode> createGain(); 127 PassRefPtr<BiquadFilterNode> createBiquadFilter(); 128 PassRefPtr<WaveShaperNode> createWaveShaper(); 129 PassRefPtr<DelayNode> createDelay(ExceptionCode&); 130 PassRefPtr<DelayNode> createDelay(double maxDelayTime, ExceptionCode&); 131 PassRefPtr<PannerNode> createPanner(); 132 PassRefPtr<ConvolverNode> createConvolver(); 133 PassRefPtr<DynamicsCompressorNode> createDynamicsCompressor(); 134 PassRefPtr<AnalyserNode> createAnalyser(); 135 PassRefPtr<ScriptProcessorNode> createScriptProcessor(size_t bufferSize, ExceptionCode&); 136 PassRefPtr<ScriptProcessorNode> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionCode&); 137 PassRefPtr<ScriptProcessorNode> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionCode&); 138 PassRefPtr<ChannelSplitterNode> createChannelSplitter(ExceptionCode&); 139 PassRefPtr<ChannelSplitterNode> createChannelSplitter(size_t numberOfOutputs, ExceptionCode&); 140 PassRefPtr<ChannelMergerNode> createChannelMerger(ExceptionCode&); 141 PassRefPtr<ChannelMergerNode> createChannelMerger(size_t numberOfInputs, ExceptionCode&); 142 PassRefPtr<OscillatorNode> createOscillator(); 143 PassRefPtr<PeriodicWave> createPeriodicWave(Float32Array* real, Float32Array* imag, ExceptionCode&); 144 145 // When a source node has no more processing to do (has finished playing), then it tells the context to dereference it. 146 void notifyNodeFinishedProcessing(AudioNode*); 147 148 // Called at the start of each render quantum. 149 void handlePreRenderTasks(); 150 151 // Called at the end of each render quantum. 152 void handlePostRenderTasks(); 153 154 // Called periodically at the end of each render quantum to dereference finished source nodes. 155 void derefFinishedSourceNodes(); 156 157 // We schedule deletion of all marked nodes at the end of each realtime render quantum. 158 void markForDeletion(AudioNode*); 159 void deleteMarkedNodes(); 160 161 // AudioContext can pull node(s) at the end of each render quantum even when they are not connected to any downstream nodes. 162 // These two methods are called by the nodes who want to add/remove themselves into/from the automatic pull lists. 163 void addAutomaticPullNode(AudioNode*); 164 void removeAutomaticPullNode(AudioNode*); 165 166 // Called right before handlePostRenderTasks() to handle nodes which need to be pulled even when they are not connected to anything. 167 void processAutomaticPullNodes(size_t framesToProcess); 168 169 // Keeps track of the number of connections made. 170 void incrementConnectionCount() 171 { 172 ASSERT(isMainThread()); 173 m_connectionCount++; 174 } 175 176 unsigned connectionCount() const { return m_connectionCount; } 177 178 // 179 // Thread Safety and Graph Locking: 180 // 181 182 void setAudioThread(ThreadIdentifier thread) { m_audioThread = thread; } // FIXME: check either not initialized or the same 183 ThreadIdentifier audioThread() const { return m_audioThread; } 184 bool isAudioThread() const; 185 186 // Returns true only after the audio thread has been started and then shutdown. 187 bool isAudioThreadFinished() { return m_isAudioThreadFinished; } 188 189 // mustReleaseLock is set to true if we acquired the lock in this method call and caller must unlock(), false if it was previously acquired. 190 void lock(bool& mustReleaseLock); 191 192 // Returns true if we own the lock. 193 // mustReleaseLock is set to true if we acquired the lock in this method call and caller must unlock(), false if it was previously acquired. 194 bool tryLock(bool& mustReleaseLock); 195 196 void unlock(); 197 198 // Returns true if this thread owns the context's lock. 199 bool isGraphOwner() const; 200 201 // Returns the maximum numuber of channels we can support. 202 static unsigned maxNumberOfChannels() { return MaxNumberOfChannels;} 203 204 class AutoLocker { 205 public: 206 explicit AutoLocker(AudioContext& context) 207 : m_context(context) 208 { 209 m_context.lock(m_mustReleaseLock); 210 } 211 212 ~AutoLocker() 213 { 214 if (m_mustReleaseLock) 215 m_context.unlock(); 216 } 217 218 private: 219 AudioContext& m_context; 220 bool m_mustReleaseLock; 221 }; 222 223 // In AudioNode::deref() a tryLock() is used for calling finishDeref(), but if it fails keep track here. 224 void addDeferredFinishDeref(AudioNode*); 225 226 // In the audio thread at the start of each render cycle, we'll call handleDeferredFinishDerefs(). 227 void handleDeferredFinishDerefs(); 228 229 // Only accessed when the graph lock is held. 230 void markSummingJunctionDirty(AudioSummingJunction*); 231 void markAudioNodeOutputDirty(AudioNodeOutput*); 232 233 // Must be called on main thread. 234 void removeMarkedSummingJunction(AudioSummingJunction*); 235 236 // EventTarget 237 virtual EventTargetInterface eventTargetInterface() const override final { return AudioContextEventTargetInterfaceType; } 238 virtual ScriptExecutionContext* scriptExecutionContext() const override final; 239 240 DEFINE_ATTRIBUTE_EVENT_LISTENER(complete); 241 242 // Reconcile ref/deref which are defined both in ThreadSafeRefCounted and EventTarget. 243 using ThreadSafeRefCounted<AudioContext>::ref; 244 using ThreadSafeRefCounted<AudioContext>::deref; 245 246 void startRendering(); 247 void fireCompletionEvent(); 248 249 static unsigned s_hardwareContextCount; 250 251 // Restrictions to change default behaviors. 252 enum BehaviorRestrictionFlags { 253 NoRestrictions = 0, 254 RequireUserGestureForAudioStartRestriction = 1 << 0, 255 RequirePageConsentForAudioStartRestriction = 1 << 1, 256 }; 257 typedef unsigned BehaviorRestrictions; 258 259 bool userGestureRequiredForAudioStart() const { return m_restrictions & RequireUserGestureForAudioStartRestriction; } 260 bool pageConsentRequiredForAudioStart() const { return m_restrictions & RequirePageConsentForAudioStartRestriction; } 261 262 void addBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions |= restriction; } 263 void removeBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions &= ~restriction; } 264 265protected: 266 explicit AudioContext(Document&); 267 AudioContext(Document&, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate); 268 269 static bool isSampleRateRangeGood(float sampleRate); 270 271private: 272 void constructCommon(); 273 274 void lazyInitialize(); 275 void uninitialize(); 276 277 // ScriptExecutionContext calls stop twice. 278 // We'd like to schedule only one stop action for them. 279 bool m_isStopScheduled; 280 static void stopDispatch(void* userData); 281 void clear(); 282 283 void scheduleNodeDeletion(); 284 static void deleteMarkedNodesDispatch(void* userData); 285 286 virtual void mediaCanStart() override; 287 288 bool m_isInitialized; 289 bool m_isAudioThreadFinished; 290 291 // The context itself keeps a reference to all source nodes. The source nodes, then reference all nodes they're connected to. 292 // In turn, these nodes reference all nodes they're connected to. All nodes are ultimately connected to the AudioDestinationNode. 293 // When the context dereferences a source node, it will be deactivated from the rendering graph along with all other nodes it is 294 // uniquely connected to. See the AudioNode::ref() and AudioNode::deref() methods for more details. 295 void refNode(AudioNode*); 296 void derefNode(AudioNode*); 297 298 // When the context goes away, there might still be some sources which haven't finished playing. 299 // Make sure to dereference them here. 300 void derefUnfinishedSourceNodes(); 301 302 RefPtr<AudioDestinationNode> m_destinationNode; 303 RefPtr<AudioListener> m_listener; 304 305 // Only accessed in the audio thread. 306 Vector<AudioNode*> m_finishedNodes; 307 308 // We don't use RefPtr<AudioNode> here because AudioNode has a more complex ref() / deref() implementation 309 // with an optional argument for refType. We need to use the special refType: RefTypeConnection 310 // Either accessed when the graph lock is held, or on the main thread when the audio thread has finished. 311 Vector<AudioNode*> m_referencedNodes; 312 313 // Accumulate nodes which need to be deleted here. 314 // This is copied to m_nodesToDelete at the end of a render cycle in handlePostRenderTasks(), where we're assured of a stable graph 315 // state which will have no references to any of the nodes in m_nodesToDelete once the context lock is released 316 // (when handlePostRenderTasks() has completed). 317 Vector<AudioNode*> m_nodesMarkedForDeletion; 318 319 // They will be scheduled for deletion (on the main thread) at the end of a render cycle (in realtime thread). 320 Vector<AudioNode*> m_nodesToDelete; 321 bool m_isDeletionScheduled; 322 323 // Only accessed when the graph lock is held. 324 HashSet<AudioSummingJunction*> m_dirtySummingJunctions; 325 HashSet<AudioNodeOutput*> m_dirtyAudioNodeOutputs; 326 void handleDirtyAudioSummingJunctions(); 327 void handleDirtyAudioNodeOutputs(); 328 329 // For the sake of thread safety, we maintain a seperate Vector of automatic pull nodes for rendering in m_renderingAutomaticPullNodes. 330 // It will be copied from m_automaticPullNodes by updateAutomaticPullNodes() at the very start or end of the rendering quantum. 331 HashSet<AudioNode*> m_automaticPullNodes; 332 Vector<AudioNode*> m_renderingAutomaticPullNodes; 333 // m_automaticPullNodesNeedUpdating keeps track if m_automaticPullNodes is modified. 334 bool m_automaticPullNodesNeedUpdating; 335 void updateAutomaticPullNodes(); 336 337 unsigned m_connectionCount; 338 339 // Graph locking. 340 Mutex m_contextGraphMutex; 341 volatile ThreadIdentifier m_audioThread; 342 volatile ThreadIdentifier m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == UndefinedThreadIdentifier 343 344 // Only accessed in the audio thread. 345 Vector<AudioNode*> m_deferredFinishDerefList; 346 347 // HRTF Database loader 348 RefPtr<HRTFDatabaseLoader> m_hrtfDatabaseLoader; 349 350 // EventTarget 351 virtual void refEventTarget() override { ref(); } 352 virtual void derefEventTarget() override { deref(); } 353 354 RefPtr<AudioBuffer> m_renderTarget; 355 356 bool m_isOfflineContext; 357 358 AsyncAudioDecoder m_audioDecoder; 359 360 // This is considering 32 is large enough for multiple channels audio. 361 // It is somewhat arbitrary and could be increased if necessary. 362 enum { MaxNumberOfChannels = 32 }; 363 364 // Number of AudioBufferSourceNodes that are active (playing). 365 std::atomic<int> m_activeSourceCount; 366 367 BehaviorRestrictions m_restrictions; 368}; 369 370} // WebCore 371 372#endif // AudioContext_h 373