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