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