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