• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "bindings/v8/ScriptWrappable.h"
29 #include "core/dom/ActiveDOMObject.h"
30 #include "core/events/EventListener.h"
31 #include "core/events/EventTarget.h"
32 #include "platform/audio/AudioBus.h"
33 #include "platform/audio/HRTFDatabaseLoader.h"
34 #include "modules/webaudio/AsyncAudioDecoder.h"
35 #include "modules/webaudio/AudioDestinationNode.h"
36 #include "wtf/HashSet.h"
37 #include "wtf/MainThread.h"
38 #include "wtf/OwnPtr.h"
39 #include "wtf/PassRefPtr.h"
40 #include "wtf/RefCounted.h"
41 #include "wtf/RefPtr.h"
42 #include "wtf/ThreadSafeRefCounted.h"
43 #include "wtf/Threading.h"
44 #include "wtf/Vector.h"
45 #include "wtf/text/AtomicStringHash.h"
46 
47 namespace WebCore {
48 
49 class AnalyserNode;
50 class AudioBuffer;
51 class AudioBufferCallback;
52 class AudioBufferSourceNode;
53 class AudioListener;
54 class AudioSummingJunction;
55 class BiquadFilterNode;
56 class ChannelMergerNode;
57 class ChannelSplitterNode;
58 class ConvolverNode;
59 class DelayNode;
60 class Document;
61 class DynamicsCompressorNode;
62 class ExceptionState;
63 class GainNode;
64 class HTMLMediaElement;
65 class MediaElementAudioSourceNode;
66 class MediaStreamAudioDestinationNode;
67 class MediaStreamAudioSourceNode;
68 class OscillatorNode;
69 class PannerNode;
70 class PeriodicWave;
71 class ScriptProcessorNode;
72 class WaveShaperNode;
73 
74 // AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
75 // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism.
76 
77 class AudioContext : public ActiveDOMObject, public ScriptWrappable, public ThreadSafeRefCounted<AudioContext>, public EventTargetWithInlineData {
78     DEFINE_EVENT_TARGET_REFCOUNTING(ThreadSafeRefCounted<AudioContext>);
79 public:
80     // Create an AudioContext for rendering to the audio hardware.
81     static PassRefPtr<AudioContext> create(Document&, ExceptionState&);
82 
83     // Deprecated: create an AudioContext for offline (non-realtime) rendering.
84     static PassRefPtr<AudioContext> create(Document&, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState&);
85 
86     virtual ~AudioContext();
87 
88     bool isInitialized() const;
89 
isOfflineContext()90     bool isOfflineContext() { return m_isOfflineContext; }
91 
92     // Returns true when initialize() was called AND all asynchronous initialization has completed.
93     bool isRunnable() const;
94 
hrtfDatabaseLoader()95     HRTFDatabaseLoader* hrtfDatabaseLoader() const { return m_hrtfDatabaseLoader.get(); }
96 
97     // Document notification
98     virtual void stop();
99 
100     Document* document() const; // ASSERTs if document no longer exists.
101     bool hasDocument();
102 
destination()103     AudioDestinationNode* destination() { return m_destinationNode.get(); }
currentSampleFrame()104     size_t currentSampleFrame() const { return m_destinationNode->currentSampleFrame(); }
currentTime()105     double currentTime() const { return m_destinationNode->currentTime(); }
sampleRate()106     float sampleRate() const { return m_destinationNode->sampleRate(); }
activeSourceCount()107     unsigned long activeSourceCount() const { return static_cast<unsigned long>(m_activeSourceCount); }
108 
109     void incrementActiveSourceCount();
110     void decrementActiveSourceCount();
111 
112     PassRefPtr<AudioBuffer> createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState&);
113     PassRefPtr<AudioBuffer> createBuffer(ArrayBuffer*, bool mixToMono, ExceptionState&);
114 
115     // Asynchronous audio file data decoding.
116     void decodeAudioData(ArrayBuffer*, PassOwnPtr<AudioBufferCallback>, PassOwnPtr<AudioBufferCallback>, ExceptionState&);
117 
listener()118     AudioListener* listener() { return m_listener.get(); }
119 
120     // The AudioNode create methods are called on the main thread (from JavaScript).
121     PassRefPtr<AudioBufferSourceNode> createBufferSource();
122     PassRefPtr<MediaElementAudioSourceNode> createMediaElementSource(HTMLMediaElement*, ExceptionState&);
123     PassRefPtr<MediaStreamAudioSourceNode> createMediaStreamSource(MediaStream*, ExceptionState&);
124     PassRefPtr<MediaStreamAudioDestinationNode> createMediaStreamDestination();
125     PassRefPtr<GainNode> createGain();
126     PassRefPtr<BiquadFilterNode> createBiquadFilter();
127     PassRefPtr<WaveShaperNode> createWaveShaper();
128     PassRefPtr<DelayNode> createDelay(ExceptionState&);
129     PassRefPtr<DelayNode> createDelay(double maxDelayTime, ExceptionState&);
130     PassRefPtr<PannerNode> createPanner();
131     PassRefPtr<ConvolverNode> createConvolver();
132     PassRefPtr<DynamicsCompressorNode> createDynamicsCompressor();
133     PassRefPtr<AnalyserNode> createAnalyser();
134     PassRefPtr<ScriptProcessorNode> createScriptProcessor(ExceptionState&);
135     PassRefPtr<ScriptProcessorNode> createScriptProcessor(size_t bufferSize, ExceptionState&);
136     PassRefPtr<ScriptProcessorNode> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState&);
137     PassRefPtr<ScriptProcessorNode> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState&);
138     PassRefPtr<ChannelSplitterNode> createChannelSplitter(ExceptionState&);
139     PassRefPtr<ChannelSplitterNode> createChannelSplitter(size_t numberOfOutputs, ExceptionState&);
140     PassRefPtr<ChannelMergerNode> createChannelMerger(ExceptionState&);
141     PassRefPtr<ChannelMergerNode> createChannelMerger(size_t numberOfInputs, ExceptionState&);
142     PassRefPtr<OscillatorNode> createOscillator();
143     PassRefPtr<PeriodicWave> createPeriodicWave(Float32Array* real, Float32Array* imag, ExceptionState&);
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.
incrementConnectionCount()170     void incrementConnectionCount()
171     {
172         ASSERT(isMainThread());
173         m_connectionCount++;
174     }
175 
connectionCount()176     unsigned connectionCount() const { return m_connectionCount; }
177 
178     //
179     // Thread Safety and Graph Locking:
180     //
181 
setAudioThread(ThreadIdentifier thread)182     void setAudioThread(ThreadIdentifier thread) { m_audioThread = thread; } // FIXME: check either not initialized or the same
audioThread()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.
isAudioThreadFinished()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.
maxNumberOfChannels()202     static unsigned maxNumberOfChannels() { return MaxNumberOfChannels;}
203 
204     class AutoLocker {
205     public:
AutoLocker(AudioContext * context)206         AutoLocker(AudioContext* context)
207             : m_context(context)
208         {
209             ASSERT(context);
210             context->lock(m_mustReleaseLock);
211         }
212 
~AutoLocker()213         ~AutoLocker()
214         {
215             if (m_mustReleaseLock)
216                 m_context->unlock();
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 const AtomicString& interfaceName() const OVERRIDE;
238     virtual ExecutionContext* executionContext() const OVERRIDE;
239 
240     DEFINE_ATTRIBUTE_EVENT_LISTENER(complete);
241 
242     void startRendering();
243     void fireCompletionEvent();
244 
245     static unsigned s_hardwareContextCount;
246 
247 protected:
248     explicit AudioContext(Document*);
249     AudioContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate);
250 
251     static bool isSampleRateRangeGood(float sampleRate);
252 
253 private:
254     void constructCommon();
255 
256     void lazyInitialize();
257     void uninitialize();
258 
259     // ExecutionContext calls stop twice.
260     // We'd like to schedule only one stop action for them.
261     bool m_isStopScheduled;
262     static void stopDispatch(void* userData);
263     void clear();
264 
265     void scheduleNodeDeletion();
266     static void deleteMarkedNodesDispatch(void* userData);
267 
268     bool m_isInitialized;
269     bool m_isAudioThreadFinished;
270 
271     // The context itself keeps a reference to all source nodes.  The source nodes, then reference all nodes they're connected to.
272     // In turn, these nodes reference all nodes they're connected to.  All nodes are ultimately connected to the AudioDestinationNode.
273     // When the context dereferences a source node, it will be deactivated from the rendering graph along with all other nodes it is
274     // uniquely connected to.  See the AudioNode::ref() and AudioNode::deref() methods for more details.
275     void refNode(AudioNode*);
276     void derefNode(AudioNode*);
277 
278     // When the context goes away, there might still be some sources which haven't finished playing.
279     // Make sure to dereference them here.
280     void derefUnfinishedSourceNodes();
281 
282     RefPtr<AudioDestinationNode> m_destinationNode;
283     RefPtr<AudioListener> m_listener;
284 
285     // Only accessed in the audio thread.
286     Vector<AudioNode*> m_finishedNodes;
287 
288     // We don't use RefPtr<AudioNode> here because AudioNode has a more complex ref() / deref() implementation
289     // with an optional argument for refType.  We need to use the special refType: RefTypeConnection
290     // Either accessed when the graph lock is held, or on the main thread when the audio thread has finished.
291     Vector<AudioNode*> m_referencedNodes;
292 
293     // Accumulate nodes which need to be deleted here.
294     // This is copied to m_nodesToDelete at the end of a render cycle in handlePostRenderTasks(), where we're assured of a stable graph
295     // state which will have no references to any of the nodes in m_nodesToDelete once the context lock is released
296     // (when handlePostRenderTasks() has completed).
297     Vector<AudioNode*> m_nodesMarkedForDeletion;
298 
299     // They will be scheduled for deletion (on the main thread) at the end of a render cycle (in realtime thread).
300     Vector<AudioNode*> m_nodesToDelete;
301     bool m_isDeletionScheduled;
302 
303     // Only accessed when the graph lock is held.
304     HashSet<AudioSummingJunction*> m_dirtySummingJunctions;
305     HashSet<AudioNodeOutput*> m_dirtyAudioNodeOutputs;
306     void handleDirtyAudioSummingJunctions();
307     void handleDirtyAudioNodeOutputs();
308 
309     // For the sake of thread safety, we maintain a seperate Vector of automatic pull nodes for rendering in m_renderingAutomaticPullNodes.
310     // It will be copied from m_automaticPullNodes by updateAutomaticPullNodes() at the very start or end of the rendering quantum.
311     HashSet<AudioNode*> m_automaticPullNodes;
312     Vector<AudioNode*> m_renderingAutomaticPullNodes;
313     // m_automaticPullNodesNeedUpdating keeps track if m_automaticPullNodes is modified.
314     bool m_automaticPullNodesNeedUpdating;
315     void updateAutomaticPullNodes();
316 
317     unsigned m_connectionCount;
318 
319     // Graph locking.
320     Mutex m_contextGraphMutex;
321     volatile ThreadIdentifier m_audioThread;
322     volatile ThreadIdentifier m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == UndefinedThreadIdentifier
323 
324     // Only accessed in the audio thread.
325     Vector<AudioNode*> m_deferredFinishDerefList;
326 
327     // HRTF Database loader
328     RefPtr<HRTFDatabaseLoader> m_hrtfDatabaseLoader;
329 
330     RefPtr<AudioBuffer> m_renderTarget;
331 
332     bool m_isOfflineContext;
333 
334     AsyncAudioDecoder m_audioDecoder;
335 
336     // This is considering 32 is large enough for multiple channels audio.
337     // It is somewhat arbitrary and could be increased if necessary.
338     enum { MaxNumberOfChannels = 32 };
339 
340     // Number of AudioBufferSourceNodes that are active (playing).
341     int m_activeSourceCount;
342 };
343 
344 } // WebCore
345 
346 #endif // AudioContext_h
347