56306fa35c751e08bee185f7c98fa0b2ffb1cd7e
[WebKit-https.git] / Source / WebCore / Modules / webaudio / BaseAudioContext.h
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2016-2021 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 #if ENABLE(WEB_AUDIO)
29 #include "ActiveDOMObject.h"
30 #include "AudioContextState.h"
31 #include "AudioDestinationNode.h"
32 #include "EventTarget.h"
33 #include "JSDOMPromiseDeferred.h"
34 #include "OscillatorType.h"
35 #include "PeriodicWaveConstraints.h"
36 #include <atomic>
37 #include <wtf/Forward.h>
38 #include <wtf/LoggerHelper.h>
39 #include <wtf/MainThread.h>
40 #include <wtf/ThreadSafeRefCounted.h>
41 #include <wtf/Threading.h>
42
43 namespace WebCore {
44
45 class AnalyserNode;
46 class AsyncAudioDecoder;
47 class AudioBuffer;
48 class AudioBufferCallback;
49 class AudioBufferSourceNode;
50 class AudioListener;
51 class AudioNodeOutput;
52 class AudioSummingJunction;
53 class AudioWorklet;
54 class BiquadFilterNode;
55 class ChannelMergerNode;
56 class ChannelSplitterNode;
57 class ConstantSourceNode;
58 class ConvolverNode;
59 class DelayNode;
60 class Document;
61 class DynamicsCompressorNode;
62 class GainNode;
63 class IIRFilterNode;
64 class MediaElementAudioSourceNode;
65 class OscillatorNode;
66 class PannerNode;
67 class PeriodicWave;
68 class ScriptProcessorNode;
69 class SecurityOrigin;
70 class StereoPannerNode;
71 class WaveShaperNode;
72
73 struct AudioIOPosition;
74 struct AudioParamDescriptor;
75
76 template<typename IDLType> class DOMPromiseDeferred;
77
78 // AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
79 // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. 
80
81 class BaseAudioContext
82     : public ActiveDOMObject
83     , public ThreadSafeRefCounted<BaseAudioContext>
84     , public EventTargetWithInlineData
85 #if !RELEASE_LOG_DISABLED
86     , public LoggerHelper
87 #endif
88 {
89     WTF_MAKE_ISO_ALLOCATED(BaseAudioContext);
90 public:
91     virtual ~BaseAudioContext();
92
93     // Reconcile ref/deref which are defined both in ThreadSafeRefCounted and EventTarget.
94     using ThreadSafeRefCounted::ref;
95     using ThreadSafeRefCounted::deref;
96
97     // This is used for lifetime testing.
98     WEBCORE_EXPORT static bool isContextAlive(uint64_t contextID);
99     uint64_t contextID() const { return m_contextID; }
100
101     Document* document() const;
102     bool isInitialized() const { return m_isInitialized; }
103     
104     virtual bool isOfflineContext() const = 0;
105     virtual AudioDestinationNode& destination() = 0;
106     virtual const AudioDestinationNode& destination() const = 0;
107
108     size_t currentSampleFrame() const { return destination().currentSampleFrame(); }
109     double currentTime() const { return destination().currentTime(); }
110     float sampleRate() const { return destination().sampleRate(); }
111     unsigned long activeSourceCount() const { return static_cast<unsigned long>(m_activeSourceCount); }
112
113     void incrementActiveSourceCount();
114     void decrementActiveSourceCount();
115
116     // Asynchronous audio file data decoding.
117     void decodeAudioData(Ref<ArrayBuffer>&&, RefPtr<AudioBufferCallback>&&, RefPtr<AudioBufferCallback>&&, Optional<Ref<DeferredPromise>>&& = WTF::nullopt);
118
119     AudioListener& listener() { return m_listener; }
120
121     using State = AudioContextState;
122     State state() const { return m_state; }
123     bool isClosed() const { return m_state == State::Closed; }
124
125     AudioWorklet& audioWorklet() { return m_worklet.get(); }
126
127     bool wouldTaintOrigin(const URL&) const;
128
129     // The AudioNode create methods are called on the main thread (from JavaScript).
130     ExceptionOr<Ref<AudioBufferSourceNode>> createBufferSource();
131     ExceptionOr<Ref<GainNode>> createGain();
132     ExceptionOr<Ref<BiquadFilterNode>> createBiquadFilter();
133     ExceptionOr<Ref<WaveShaperNode>> createWaveShaper();
134     ExceptionOr<Ref<DelayNode>> createDelay(double maxDelayTime);
135     ExceptionOr<Ref<PannerNode>> createPanner();
136     ExceptionOr<Ref<ConvolverNode>> createConvolver();
137     ExceptionOr<Ref<DynamicsCompressorNode>> createDynamicsCompressor();
138     ExceptionOr<Ref<AnalyserNode>> createAnalyser();
139     ExceptionOr<Ref<ScriptProcessorNode>> createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels);
140     ExceptionOr<Ref<ChannelSplitterNode>> createChannelSplitter(size_t numberOfOutputs);
141     ExceptionOr<Ref<ChannelMergerNode>> createChannelMerger(size_t numberOfInputs);
142     ExceptionOr<Ref<OscillatorNode>> createOscillator();
143     ExceptionOr<Ref<PeriodicWave>> createPeriodicWave(Vector<float>&& real, Vector<float>&& imaginary, const PeriodicWaveConstraints& = { });
144     ExceptionOr<Ref<ConstantSourceNode>> createConstantSource();
145     ExceptionOr<Ref<StereoPannerNode>> createStereoPanner();
146     ExceptionOr<Ref<IIRFilterNode>> createIIRFilter(ScriptExecutionContext&, Vector<double>&& feedforward, Vector<double>&& feedback);
147     ExceptionOr<Ref<AudioBuffer>> createBuffer(unsigned numberOfChannels, unsigned length, float sampleRate);
148
149     // Called at the start of each render quantum.
150     void handlePreRenderTasks(const AudioIOPosition& outputPosition);
151
152     AudioIOPosition outputPosition();
153
154     // Called at the end of each render quantum.
155     void handlePostRenderTasks();
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(Thread& thread) { m_audioThread = &thread; } // FIXME: check either not initialized or the same
183     bool isAudioThread() const { return m_audioThread == &Thread::current(); }
184
185     // Returns true only after the audio thread has been started and then shutdown.
186     bool isAudioThreadFinished() const { 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 { return m_graphOwnerThread == &Thread::current(); }
199
200     // This is considering 32 is large enough for multiple channels audio.
201     // It is somewhat arbitrary and could be increased if necessary.
202     static constexpr unsigned maxNumberOfChannels = 32;
203     
204     // In AudioNode::decrementConnectionCount() a tryLock() is used for calling decrementConnectionCountWithLock(), but if it fails keep track here.
205     void addDeferredDecrementConnectionCount(AudioNode*);
206
207     // Only accessed when the graph lock is held.
208     void markSummingJunctionDirty(AudioSummingJunction*);
209     void markAudioNodeOutputDirty(AudioNodeOutput*);
210
211     // Must be called on main thread.
212     void removeMarkedSummingJunction(AudioSummingJunction*);
213
214     // EventTarget
215     ScriptExecutionContext* scriptExecutionContext() const final;
216
217     void isPlayingAudioDidChange();
218
219     virtual void sourceNodeWillBeginPlayback(AudioNode&);
220     // When a source node has no more processing to do (has finished playing), then it tells the context to dereference it.
221     void sourceNodeDidFinishPlayback(AudioNode&);
222
223 #if !RELEASE_LOG_DISABLED
224     const Logger& logger() const override { return m_logger.get(); }
225     const void* logIdentifier() const final { return m_logIdentifier; }
226     WTFLogChannel& logChannel() const final;
227     const void* nextAudioNodeLogIdentifier() { return childLogIdentifier(m_logIdentifier, ++m_nextAudioNodeIdentifier); }
228     const void* nextAudioParameterLogIdentifier() { return childLogIdentifier(m_logIdentifier, ++m_nextAudioParameterIdentifier); }
229 #endif
230
231     void postTask(Function<void()>&&);
232     bool isStopped() const { return m_isStopScheduled; }
233     const SecurityOrigin* origin() const;
234     void addConsoleMessage(MessageSource, MessageLevel, const String& message);
235
236     class AutoLocker {
237     public:
238         explicit AutoLocker(BaseAudioContext& context)
239             : m_context(context)
240         {
241             m_context.lock(m_mustReleaseLock);
242         }
243
244         ~AutoLocker()
245         {
246             if (m_mustReleaseLock)
247                 m_context.unlock();
248         }
249
250     private:
251         BaseAudioContext& m_context;
252         bool m_mustReleaseLock;
253     };
254
255     virtual void lazyInitialize();
256
257     static bool isSupportedSampleRate(float sampleRate);
258
259     PeriodicWave& periodicWave(OscillatorType);
260
261     void addAudioParamDescriptors(const String& processorName, Vector<AudioParamDescriptor>&&);
262     const HashMap<String, Vector<AudioParamDescriptor>>& parameterDescriptorMap() const { return m_parameterDescriptorMap; }
263
264 protected:
265     explicit BaseAudioContext(Document&);
266     
267     void clearPendingActivity();
268     void setPendingActivity();
269
270     void lockInternal(bool& mustReleaseLock);
271
272     virtual void uninitialize();
273
274 #if !RELEASE_LOG_DISABLED
275     const char* logClassName() const final { return "BaseAudioContext"; }
276 #endif
277
278     void addReaction(State, DOMPromiseDeferred<void>&&);
279     void setState(State);
280
281     void clear();
282
283 private:
284     void scheduleNodeDeletion();
285     void workletIsReady();
286
287     // When source nodes begin playing, the BaseAudioContext keeps them alive inside m_referencedSourceNodes.
288     // When the nodes stop playing, a flag gets set on the AudioNode accordingly. After each rendering quantum,
289     // we call derefFinishedSourceNodes() to remove those nodes from m_referencedSourceNodes since we no longer
290     // need to keep them alive.
291     void refSourceNode(AudioNode&);
292     void derefSourceNode(AudioNode&);
293
294     // Called periodically at the end of each render quantum to dereference finished source nodes.
295     void derefFinishedSourceNodes();
296
297     // In the audio thread at the start of each render cycle, we'll call handleDeferredDecrementConnectionCounts().
298     void handleDeferredDecrementConnectionCounts();
299
300     // EventTarget
301     EventTargetInterface eventTargetInterface() const final;
302     void refEventTarget() override { ref(); }
303     void derefEventTarget() override { deref(); }
304
305     // ActiveDOMObject API.
306     void stop() 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     void handleDirtyAudioSummingJunctions();
313     void handleDirtyAudioNodeOutputs();
314
315     void updateAutomaticPullNodes();
316
317 #if !RELEASE_LOG_DISABLED
318     Ref<Logger> m_logger;
319     const void* m_logIdentifier;
320     uint64_t m_nextAudioNodeIdentifier { 0 };
321     uint64_t m_nextAudioParameterIdentifier { 0 };
322 #endif
323
324     uint64_t m_contextID;
325
326     Ref<AudioWorklet> m_worklet;
327
328     // Either accessed when the graph lock is held, or on the main thread when the audio thread has finished.
329     Vector<AudioConnectionRefPtr<AudioNode>> m_referencedSourceNodes;
330
331     // Accumulate nodes which need to be deleted here.
332     // This is copied to m_nodesToDelete at the end of a render cycle in handlePostRenderTasks(), where we're assured of a stable graph
333     // state which will have no references to any of the nodes in m_nodesToDelete once the context lock is released
334     // (when handlePostRenderTasks() has completed).
335     Vector<AudioNode*> m_nodesMarkedForDeletion;
336
337     // They will be scheduled for deletion (on the main thread) at the end of a render cycle (in realtime thread).
338     Vector<AudioNode*> m_nodesToDelete;
339
340     // Only accessed when the graph lock is held.
341     HashSet<AudioSummingJunction*> m_dirtySummingJunctions;
342     HashSet<AudioNodeOutput*> m_dirtyAudioNodeOutputs;
343
344     // For the sake of thread safety, we maintain a seperate Vector of automatic pull nodes for rendering in m_renderingAutomaticPullNodes.
345     // It will be copied from m_automaticPullNodes by updateAutomaticPullNodes() at the very start or end of the rendering quantum.
346     HashSet<AudioNode*> m_automaticPullNodes;
347     Vector<AudioNode*> m_renderingAutomaticPullNodes;
348     // Only accessed in the audio thread.
349     Vector<AudioNode*> m_deferredBreakConnectionList;
350     Vector<Vector<DOMPromiseDeferred<void>>> m_stateReactions;
351
352     Ref<AudioListener> m_listener;
353
354     std::atomic<Thread*> m_audioThread;
355     std::atomic<Thread*> m_graphOwnerThread; // if the lock is held then this is the thread which owns it, otherwise == nullptr.
356
357     std::unique_ptr<AsyncAudioDecoder> m_audioDecoder;
358
359     RefPtr<PendingActivity<BaseAudioContext>> m_pendingActivity;
360
361     AudioIOPosition m_outputPosition;
362
363     HashMap<String, Vector<AudioParamDescriptor>> m_parameterDescriptorMap;
364
365     // These are cached per audio context for performance reasons. They cannot be
366     // static because they rely on the sample rate.
367     RefPtr<PeriodicWave> m_cachedPeriodicWaveSine;
368     RefPtr<PeriodicWave> m_cachedPeriodicWaveSquare;
369     RefPtr<PeriodicWave> m_cachedPeriodicWaveSawtooth;
370     RefPtr<PeriodicWave> m_cachedPeriodicWaveTriangle;
371
372     // Number of AudioBufferSourceNodes that are active (playing).
373     std::atomic<int> m_activeSourceCount;
374
375     unsigned m_connectionCount { 0 };
376     State m_state { State::Suspended };
377     Lock m_contextGraphLock;
378     bool m_isDeletionScheduled { false };
379     bool m_isStopScheduled { false };
380     bool m_isInitialized { false };
381     bool m_isAudioThreadFinished { false };
382     bool m_automaticPullNodesNeedUpdating { false };
383     bool m_hasFinishedAudioSourceNodes { false };
384 };
385
386 } // WebCore
387
388 #endif // ENABLE(WEB_AUDIO)