[WebIDL] Add support for converting dictionaries to JS
[WebKit-https.git] / Source / WebCore / Modules / webaudio / AudioContext.cpp
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 #include "config.h"
27
28 #if ENABLE(WEB_AUDIO)
29
30 #include "AudioContext.h"
31
32 #include "AnalyserNode.h"
33 #include "AsyncAudioDecoder.h"
34 #include "AudioBuffer.h"
35 #include "AudioBufferCallback.h"
36 #include "AudioBufferSourceNode.h"
37 #include "AudioListener.h"
38 #include "AudioNodeInput.h"
39 #include "AudioNodeOutput.h"
40 #include "BiquadFilterNode.h"
41 #include "ChannelMergerNode.h"
42 #include "ChannelSplitterNode.h"
43 #include "ConvolverNode.h"
44 #include "DefaultAudioDestinationNode.h"
45 #include "DelayNode.h"
46 #include "Document.h"
47 #include "DynamicsCompressorNode.h"
48 #include "EventNames.h"
49 #include "ExceptionCode.h"
50 #include "FFTFrame.h"
51 #include "Frame.h"
52 #include "GainNode.h"
53 #include "GenericEventQueue.h"
54 #include "HRTFDatabaseLoader.h"
55 #include "HRTFPanner.h"
56 #include "JSDOMPromise.h"
57 #include "NetworkingContext.h"
58 #include "OfflineAudioCompletionEvent.h"
59 #include "OfflineAudioDestinationNode.h"
60 #include "OscillatorNode.h"
61 #include "Page.h"
62 #include "PannerNode.h"
63 #include "PeriodicWave.h"
64 #include "ScriptController.h"
65 #include "ScriptProcessorNode.h"
66 #include "WaveShaperNode.h"
67 #include <inspector/ScriptCallStack.h>
68
69 #if ENABLE(MEDIA_STREAM)
70 #include "MediaStream.h"
71 #include "MediaStreamAudioDestinationNode.h"
72 #include "MediaStreamAudioSource.h"
73 #include "MediaStreamAudioSourceNode.h"
74 #endif
75
76 #if ENABLE(VIDEO)
77 #include "HTMLMediaElement.h"
78 #include "MediaElementAudioSourceNode.h"
79 #endif
80
81 #if DEBUG_AUDIONODE_REFERENCES
82 #include <stdio.h>
83 #endif
84
85 #if USE(GSTREAMER)
86 #include "GStreamerUtilities.h"
87 #endif
88
89 #if PLATFORM(IOS)
90 #include "ScriptController.h"
91 #include "Settings.h"
92 #endif
93
94 #include <runtime/ArrayBuffer.h>
95 #include <wtf/Atomics.h>
96 #include <wtf/MainThread.h>
97 #include <wtf/Ref.h>
98 #include <wtf/RefCounted.h>
99 #include <wtf/text/WTFString.h>
100
101 // FIXME: check the proper way to reference an undefined thread ID
102 const int UndefinedThreadIdentifier = 0xffffffff;
103
104 const unsigned MaxPeriodicWaveLength = 4096;
105
106 namespace WebCore {
107     
108 bool AudioContext::isSampleRateRangeGood(float sampleRate)
109 {
110     // FIXME: It would be nice if the minimum sample-rate could be less than 44.1KHz,
111     // but that will require some fixes in HRTFPanner::fftSizeForSampleRate(), and some testing there.
112     return sampleRate >= 44100 && sampleRate <= 96000;
113 }
114
115 // Don't allow more than this number of simultaneous AudioContexts talking to hardware.
116 const unsigned MaxHardwareContexts = 4;
117 unsigned AudioContext::s_hardwareContextCount = 0;
118     
119 RefPtr<AudioContext> AudioContext::create(Document& document)
120 {
121     ASSERT(isMainThread());
122     if (s_hardwareContextCount >= MaxHardwareContexts)
123         return nullptr;
124
125     RefPtr<AudioContext> audioContext(adoptRef(new AudioContext(document)));
126     audioContext->suspendIfNeeded();
127     return audioContext;
128 }
129
130 // Constructor for rendering to the audio hardware.
131 AudioContext::AudioContext(Document& document)
132     : ActiveDOMObject(&document)
133     , m_mediaSession(PlatformMediaSession::create(*this))
134     , m_eventQueue(std::make_unique<GenericEventQueue>(*this))
135     , m_graphOwnerThread(UndefinedThreadIdentifier)
136 {
137     constructCommon();
138
139     m_destinationNode = DefaultAudioDestinationNode::create(*this);
140
141     // Initialize the destination node's muted state to match the page's current muted state.
142     pageMutedStateDidChange();
143 }
144
145 // Constructor for offline (non-realtime) rendering.
146 AudioContext::AudioContext(Document& document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
147     : ActiveDOMObject(&document)
148     , m_isOfflineContext(true)
149     , m_mediaSession(PlatformMediaSession::create(*this))
150     , m_eventQueue(std::make_unique<GenericEventQueue>(*this))
151     , m_graphOwnerThread(UndefinedThreadIdentifier)
152 {
153     constructCommon();
154
155     // Create a new destination for offline rendering.
156     m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
157     m_destinationNode = OfflineAudioDestinationNode::create(*this, m_renderTarget.get());
158 }
159
160 void AudioContext::constructCommon()
161 {
162     // According to spec AudioContext must die only after page navigate.
163     // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method.
164     setPendingActivity(this);
165
166 #if USE(GSTREAMER)
167     initializeGStreamer();
168 #endif
169
170     FFTFrame::initialize();
171     
172     m_listener = AudioListener::create();
173
174 #if PLATFORM(IOS)
175     if (!document()->settings() || document()->settings()->audioPlaybackRequiresUserGesture())
176         addBehaviorRestriction(RequireUserGestureForAudioStartRestriction);
177     else
178         m_restrictions = NoRestrictions;
179 #endif
180
181 #if PLATFORM(COCOA)
182     addBehaviorRestriction(RequirePageConsentForAudioStartRestriction);
183 #endif
184
185     m_mediaSession->setCanProduceAudio(true);
186 }
187
188 AudioContext::~AudioContext()
189 {
190 #if DEBUG_AUDIONODE_REFERENCES
191     fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this);
192 #endif
193     ASSERT(!m_isInitialized);
194     ASSERT(m_isStopScheduled);
195     ASSERT(m_nodesToDelete.isEmpty());
196     ASSERT(m_referencedNodes.isEmpty());
197     ASSERT(m_finishedNodes.isEmpty()); // FIXME (bug 105870): This assertion fails on tests sometimes.
198     ASSERT(m_automaticPullNodes.isEmpty());
199     if (m_automaticPullNodesNeedUpdating)
200         m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
201     ASSERT(m_renderingAutomaticPullNodes.isEmpty());
202     // FIXME: Can we assert that m_deferredFinishDerefList is empty?
203 }
204
205 void AudioContext::lazyInitialize()
206 {
207     if (m_isInitialized)
208         return;
209
210     // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
211     ASSERT(!m_isAudioThreadFinished);
212     if (m_isAudioThreadFinished)
213         return;
214
215     if (m_destinationNode) {
216         m_destinationNode->initialize();
217
218         if (!isOfflineContext()) {
219             document()->addAudioProducer(this);
220
221             // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
222             // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
223             // NOTE: for now default AudioContext does not need an explicit startRendering() call from JavaScript.
224             // We may want to consider requiring it for symmetry with OfflineAudioContext.
225             startRendering();
226             ++s_hardwareContextCount;
227         }
228     }
229     m_isInitialized = true;
230 }
231
232 void AudioContext::clear()
233 {
234     // We have to release our reference to the destination node before the context will ever be deleted since the destination node holds a reference to the context.
235     if (m_destinationNode)
236         m_destinationNode = nullptr;
237
238     // Audio thread is dead. Nobody will schedule node deletion action. Let's do it ourselves.
239     do {
240         deleteMarkedNodes();
241         m_nodesToDelete.appendVector(m_nodesMarkedForDeletion);
242         m_nodesMarkedForDeletion.clear();
243     } while (m_nodesToDelete.size());
244
245     // It was set in constructCommon.
246     unsetPendingActivity(this);
247 }
248
249 void AudioContext::uninitialize()
250 {
251     ASSERT(isMainThread());
252
253     if (!m_isInitialized)
254         return;
255
256     // This stops the audio thread and all audio rendering.
257     m_destinationNode->uninitialize();
258
259     // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
260     m_isAudioThreadFinished = true;
261
262     if (!isOfflineContext()) {
263         document()->removeAudioProducer(this);
264
265         ASSERT(s_hardwareContextCount);
266         --s_hardwareContextCount;
267
268         // Offline contexts move to 'Closed' state when dispatching the completion event.
269         setState(State::Closed);
270     }
271
272     // Get rid of the sources which may still be playing.
273     derefUnfinishedSourceNodes();
274
275     m_isInitialized = false;
276 }
277
278 bool AudioContext::isInitialized() const
279 {
280     return m_isInitialized;
281 }
282
283 void AudioContext::addReaction(State state, DOMPromise<void>&& promise)
284 {
285     size_t stateIndex = static_cast<size_t>(state);
286     if (stateIndex >= m_stateReactions.size())
287         m_stateReactions.resize(stateIndex + 1);
288
289     m_stateReactions[stateIndex].append(WTFMove(promise));
290 }
291
292 void AudioContext::setState(State state)
293 {
294     if (m_state == state)
295         return;
296
297     m_state = state;
298     m_eventQueue->enqueueEvent(Event::create(eventNames().statechangeEvent, true, false));
299
300     size_t stateIndex = static_cast<size_t>(state);
301     if (stateIndex >= m_stateReactions.size())
302         return;
303
304     Vector<DOMPromise<void>> reactions;
305     m_stateReactions[stateIndex].swap(reactions);
306
307     for (auto& promise : reactions)
308         promise.resolve();
309 }
310
311 void AudioContext::stop()
312 {
313     ASSERT(isMainThread());
314
315     // Usually ScriptExecutionContext calls stop twice.
316     if (m_isStopScheduled)
317         return;
318     m_isStopScheduled = true;
319
320     document()->updateIsPlayingMedia();
321
322     m_eventQueue->close();
323
324     // Don't call uninitialize() immediately here because the ScriptExecutionContext is in the middle
325     // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
326     // ActiveDOMObjects so let's schedule uninitialize() to be called later.
327     // FIXME: see if there's a more direct way to handle this issue.
328     // FIXME: This sounds very wrong. The whole idea of stop() is that it stops everything, and if we
329     // schedule some observable work for later, the work likely happens at an inappropriate time.
330     callOnMainThread([this] {
331         uninitialize();
332         clear();
333     });
334 }
335
336 bool AudioContext::canSuspendForDocumentSuspension() const
337 {
338     // FIXME: We should be able to suspend while rendering as well with some more code.
339     return m_state == State::Suspended || m_state == State::Closed;
340 }
341
342 const char* AudioContext::activeDOMObjectName() const
343 {
344     return "AudioContext";
345 }
346
347 Document* AudioContext::document() const
348 {
349     ASSERT(m_scriptExecutionContext);
350     return downcast<Document>(m_scriptExecutionContext);
351 }
352
353 const Document* AudioContext::hostingDocument() const
354 {
355     return downcast<Document>(m_scriptExecutionContext);
356 }
357
358 String AudioContext::sourceApplicationIdentifier() const
359 {
360     Document* document = this->document();
361     if (Frame* frame = document ? document->frame() : nullptr) {
362         if (NetworkingContext* networkingContext = frame->loader().networkingContext())
363             return networkingContext->sourceApplicationIdentifier();
364     }
365     return emptyString();
366 }
367
368 ExceptionOr<Ref<AudioBuffer>> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
369 {
370     auto audioBuffer = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
371     if (!audioBuffer)
372         return Exception { NOT_SUPPORTED_ERR };
373     return audioBuffer.releaseNonNull();
374 }
375
376 ExceptionOr<Ref<AudioBuffer>> AudioContext::createBuffer(ArrayBuffer& arrayBuffer, bool mixToMono)
377 {
378     auto audioBuffer = AudioBuffer::createFromAudioFileData(arrayBuffer.data(), arrayBuffer.byteLength(), mixToMono, sampleRate());
379     if (!audioBuffer)
380         return Exception { SYNTAX_ERR };
381     return audioBuffer.releaseNonNull();
382 }
383
384 void AudioContext::decodeAudioData(Ref<ArrayBuffer>&& audioData, RefPtr<AudioBufferCallback>&& successCallback, RefPtr<AudioBufferCallback>&& errorCallback)
385 {
386     m_audioDecoder.decodeAsync(WTFMove(audioData), sampleRate(), WTFMove(successCallback), WTFMove(errorCallback));
387 }
388
389 Ref<AudioBufferSourceNode> AudioContext::createBufferSource()
390 {
391     ASSERT(isMainThread());
392     lazyInitialize();
393     Ref<AudioBufferSourceNode> node = AudioBufferSourceNode::create(*this, m_destinationNode->sampleRate());
394
395     // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
396     // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
397     refNode(node);
398
399     return node;
400 }
401
402 #if ENABLE(VIDEO)
403
404 ExceptionOr<Ref<MediaElementAudioSourceNode>> AudioContext::createMediaElementSource(HTMLMediaElement& mediaElement)
405 {
406     ASSERT(isMainThread());
407     lazyInitialize();
408     
409     if (mediaElement.audioSourceNode())
410         return Exception { INVALID_STATE_ERR };
411
412     auto node = MediaElementAudioSourceNode::create(*this, mediaElement);
413
414     mediaElement.setAudioSourceNode(node.ptr());
415
416     refNode(node.get()); // context keeps reference until node is disconnected
417     return WTFMove(node);
418 }
419
420 #endif
421
422 #if ENABLE(MEDIA_STREAM)
423
424 ExceptionOr<Ref<MediaStreamAudioSourceNode>> AudioContext::createMediaStreamSource(MediaStream& mediaStream)
425 {
426     ASSERT(isMainThread());
427
428     auto audioTracks = mediaStream.getAudioTracks();
429     if (audioTracks.isEmpty())
430         return Exception { INVALID_STATE_ERR };
431
432     MediaStreamTrack* providerTrack = nullptr;
433     for (auto& track : audioTracks) {
434         if (track->audioSourceProvider()) {
435             providerTrack = track.get();
436             break;
437         }
438     }
439     if (!providerTrack)
440         return Exception { INVALID_STATE_ERR };
441
442     lazyInitialize();
443
444     auto node = MediaStreamAudioSourceNode::create(*this, mediaStream, *providerTrack);
445     node->setFormat(2, sampleRate());
446
447     refNode(node); // context keeps reference until node is disconnected
448     return WTFMove(node);
449 }
450
451 Ref<MediaStreamAudioDestinationNode> AudioContext::createMediaStreamDestination()
452 {
453     // FIXME: Add support for an optional argument which specifies the number of channels.
454     // FIXME: The default should probably be stereo instead of mono.
455     return MediaStreamAudioDestinationNode::create(*this, 1);
456 }
457
458 #endif
459
460 ExceptionOr<Ref<ScriptProcessorNode>> AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels)
461 {
462     ASSERT(isMainThread());
463     lazyInitialize();
464     auto node = ScriptProcessorNode::create(*this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
465
466     if (!node)
467         return Exception { INDEX_SIZE_ERR };
468
469     refNode(*node); // context keeps reference until we stop making javascript rendering callbacks
470     return node.releaseNonNull();
471 }
472
473 Ref<BiquadFilterNode> AudioContext::createBiquadFilter()
474 {
475     ASSERT(isMainThread());
476     lazyInitialize();
477     return BiquadFilterNode::create(*this, m_destinationNode->sampleRate());
478 }
479
480 Ref<WaveShaperNode> AudioContext::createWaveShaper()
481 {
482     ASSERT(isMainThread());
483     lazyInitialize();
484     return WaveShaperNode::create(*this);
485 }
486
487 Ref<PannerNode> AudioContext::createPanner()
488 {
489     ASSERT(isMainThread());
490     lazyInitialize();
491     return PannerNode::create(*this, m_destinationNode->sampleRate());
492 }
493
494 Ref<ConvolverNode> AudioContext::createConvolver()
495 {
496     ASSERT(isMainThread());
497     lazyInitialize();
498     return ConvolverNode::create(*this, m_destinationNode->sampleRate());
499 }
500
501 Ref<DynamicsCompressorNode> AudioContext::createDynamicsCompressor()
502 {
503     ASSERT(isMainThread());
504     lazyInitialize();
505     return DynamicsCompressorNode::create(*this, m_destinationNode->sampleRate());
506 }
507
508 Ref<AnalyserNode> AudioContext::createAnalyser()
509 {
510     ASSERT(isMainThread());
511     lazyInitialize();
512     return AnalyserNode::create(*this, m_destinationNode->sampleRate());
513 }
514
515 Ref<GainNode> AudioContext::createGain()
516 {
517     ASSERT(isMainThread());
518     lazyInitialize();
519     return GainNode::create(*this, m_destinationNode->sampleRate());
520 }
521
522 ExceptionOr<Ref<DelayNode>> AudioContext::createDelay(double maxDelayTime)
523 {
524     ASSERT(isMainThread());
525     lazyInitialize();
526     return DelayNode::create(*this, m_destinationNode->sampleRate(), maxDelayTime);
527 }
528
529 ExceptionOr<Ref<ChannelSplitterNode>> AudioContext::createChannelSplitter(size_t numberOfOutputs)
530 {
531     ASSERT(isMainThread());
532     lazyInitialize();
533     auto node = ChannelSplitterNode::create(*this, m_destinationNode->sampleRate(), numberOfOutputs);
534     if (!node)
535         return Exception { INDEX_SIZE_ERR };
536     return node.releaseNonNull();
537 }
538
539 ExceptionOr<Ref<ChannelMergerNode>> AudioContext::createChannelMerger(size_t numberOfInputs)
540 {
541     ASSERT(isMainThread());
542     lazyInitialize();
543     auto node = ChannelMergerNode::create(*this, m_destinationNode->sampleRate(), numberOfInputs);
544     if (!node)
545         return Exception { INDEX_SIZE_ERR };
546     return node.releaseNonNull();
547 }
548
549 Ref<OscillatorNode> AudioContext::createOscillator()
550 {
551     ASSERT(isMainThread());
552     lazyInitialize();
553
554     Ref<OscillatorNode> node = OscillatorNode::create(*this, m_destinationNode->sampleRate());
555
556     // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
557     // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
558     refNode(node);
559
560     return node;
561 }
562
563 ExceptionOr<Ref<PeriodicWave>> AudioContext::createPeriodicWave(Float32Array& real, Float32Array& imaginary)
564 {
565     ASSERT(isMainThread());
566     if (real.length() != imaginary.length() || (real.length() > MaxPeriodicWaveLength) || !real.length())
567         return Exception { INDEX_SIZE_ERR };
568     lazyInitialize();
569     return PeriodicWave::create(sampleRate(), real, imaginary);
570 }
571
572 void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
573 {
574     ASSERT(isAudioThread());
575     m_finishedNodes.append(node);
576 }
577
578 void AudioContext::derefFinishedSourceNodes()
579 {
580     ASSERT(isGraphOwner());
581     ASSERT(isAudioThread() || isAudioThreadFinished());
582     for (auto& node : m_finishedNodes)
583         derefNode(*node);
584
585     m_finishedNodes.clear();
586 }
587
588 void AudioContext::refNode(AudioNode& node)
589 {
590     ASSERT(isMainThread());
591     AutoLocker locker(*this);
592     
593     node.ref(AudioNode::RefTypeConnection);
594     m_referencedNodes.append(&node);
595 }
596
597 void AudioContext::derefNode(AudioNode& node)
598 {
599     ASSERT(isGraphOwner());
600     
601     node.deref(AudioNode::RefTypeConnection);
602
603     ASSERT(m_referencedNodes.contains(&node));
604     m_referencedNodes.removeFirst(&node);
605 }
606
607 void AudioContext::derefUnfinishedSourceNodes()
608 {
609     ASSERT(isMainThread() && isAudioThreadFinished());
610     for (auto& node : m_referencedNodes)
611         node->deref(AudioNode::RefTypeConnection);
612
613     m_referencedNodes.clear();
614 }
615
616 void AudioContext::lock(bool& mustReleaseLock)
617 {
618     // Don't allow regular lock in real-time audio thread.
619     ASSERT(isMainThread());
620
621     ThreadIdentifier thisThread = currentThread();
622
623     if (thisThread == m_graphOwnerThread) {
624         // We already have the lock.
625         mustReleaseLock = false;
626     } else {
627         // Acquire the lock.
628         m_contextGraphMutex.lock();
629         m_graphOwnerThread = thisThread;
630         mustReleaseLock = true;
631     }
632 }
633
634 bool AudioContext::tryLock(bool& mustReleaseLock)
635 {
636     ThreadIdentifier thisThread = currentThread();
637     bool isAudioThread = thisThread == audioThread();
638
639     // Try to catch cases of using try lock on main thread - it should use regular lock.
640     ASSERT(isAudioThread || isAudioThreadFinished());
641     
642     if (!isAudioThread) {
643         // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
644         lock(mustReleaseLock);
645         return true;
646     }
647     
648     bool hasLock;
649     
650     if (thisThread == m_graphOwnerThread) {
651         // Thread already has the lock.
652         hasLock = true;
653         mustReleaseLock = false;
654     } else {
655         // Don't already have the lock - try to acquire it.
656         hasLock = m_contextGraphMutex.tryLock();
657         
658         if (hasLock)
659             m_graphOwnerThread = thisThread;
660
661         mustReleaseLock = hasLock;
662     }
663     
664     return hasLock;
665 }
666
667 void AudioContext::unlock()
668 {
669     ASSERT(currentThread() == m_graphOwnerThread);
670
671     m_graphOwnerThread = UndefinedThreadIdentifier;
672     m_contextGraphMutex.unlock();
673 }
674
675 bool AudioContext::isAudioThread() const
676 {
677     return currentThread() == m_audioThread;
678 }
679
680 bool AudioContext::isGraphOwner() const
681 {
682     return currentThread() == m_graphOwnerThread;
683 }
684
685 void AudioContext::addDeferredFinishDeref(AudioNode* node)
686 {
687     ASSERT(isAudioThread());
688     m_deferredFinishDerefList.append(node);
689 }
690
691 void AudioContext::handlePreRenderTasks()
692 {
693     ASSERT(isAudioThread());
694
695     // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
696     // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
697     bool mustReleaseLock;
698     if (tryLock(mustReleaseLock)) {
699         // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
700         handleDirtyAudioSummingJunctions();
701         handleDirtyAudioNodeOutputs();
702
703         updateAutomaticPullNodes();
704
705         if (mustReleaseLock)
706             unlock();
707     }
708 }
709
710 void AudioContext::handlePostRenderTasks()
711 {
712     ASSERT(isAudioThread());
713
714     // Must use a tryLock() here too. Don't worry, the lock will very rarely be contended and this method is called frequently.
715     // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
716     // from the render graph (in which case they'll render silence).
717     bool mustReleaseLock;
718     if (tryLock(mustReleaseLock)) {
719         // Take care of finishing any derefs where the tryLock() failed previously.
720         handleDeferredFinishDerefs();
721
722         // Dynamically clean up nodes which are no longer needed.
723         derefFinishedSourceNodes();
724
725         // Don't delete in the real-time thread. Let the main thread do it.
726         // Ref-counted objects held by certain AudioNodes may not be thread-safe.
727         scheduleNodeDeletion();
728
729         // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
730         handleDirtyAudioSummingJunctions();
731         handleDirtyAudioNodeOutputs();
732
733         updateAutomaticPullNodes();
734
735         if (mustReleaseLock)
736             unlock();
737     }
738 }
739
740 void AudioContext::handleDeferredFinishDerefs()
741 {
742     ASSERT(isAudioThread() && isGraphOwner());
743     for (auto& node : m_deferredFinishDerefList)
744         node->finishDeref(AudioNode::RefTypeConnection);
745     
746     m_deferredFinishDerefList.clear();
747 }
748
749 void AudioContext::markForDeletion(AudioNode* node)
750 {
751     ASSERT(isGraphOwner());
752
753     if (isAudioThreadFinished())
754         m_nodesToDelete.append(node);
755     else
756         m_nodesMarkedForDeletion.append(node);
757
758     // This is probably the best time for us to remove the node from automatic pull list,
759     // since all connections are gone and we hold the graph lock. Then when handlePostRenderTasks()
760     // gets a chance to schedule the deletion work, updateAutomaticPullNodes() also gets a chance to
761     // modify m_renderingAutomaticPullNodes.
762     removeAutomaticPullNode(node);
763 }
764
765 void AudioContext::scheduleNodeDeletion()
766 {
767     bool isGood = m_isInitialized && isGraphOwner();
768     ASSERT(isGood);
769     if (!isGood)
770         return;
771
772     // Make sure to call deleteMarkedNodes() on main thread.    
773     if (m_nodesMarkedForDeletion.size() && !m_isDeletionScheduled) {
774         m_nodesToDelete.appendVector(m_nodesMarkedForDeletion);
775         m_nodesMarkedForDeletion.clear();
776
777         m_isDeletionScheduled = true;
778
779         callOnMainThread([protectedThis = makeRef(*this)]() mutable {
780             protectedThis->deleteMarkedNodes();
781         });
782     }
783 }
784
785 void AudioContext::deleteMarkedNodes()
786 {
787     ASSERT(isMainThread());
788
789     // Protect this object from being deleted before we release the mutex locked by AutoLocker.
790     Ref<AudioContext> protectedThis(*this);
791     {
792         AutoLocker locker(*this);
793
794         while (m_nodesToDelete.size()) {
795             AudioNode* node = m_nodesToDelete.takeLast();
796
797             // Before deleting the node, clear out any AudioNodeInputs from m_dirtySummingJunctions.
798             unsigned numberOfInputs = node->numberOfInputs();
799             for (unsigned i = 0; i < numberOfInputs; ++i)
800                 m_dirtySummingJunctions.remove(node->input(i));
801
802             // Before deleting the node, clear out any AudioNodeOutputs from m_dirtyAudioNodeOutputs.
803             unsigned numberOfOutputs = node->numberOfOutputs();
804             for (unsigned i = 0; i < numberOfOutputs; ++i)
805                 m_dirtyAudioNodeOutputs.remove(node->output(i));
806
807             // Finally, delete it.
808             delete node;
809         }
810         m_isDeletionScheduled = false;
811     }
812 }
813
814 void AudioContext::markSummingJunctionDirty(AudioSummingJunction* summingJunction)
815 {
816     ASSERT(isGraphOwner());    
817     m_dirtySummingJunctions.add(summingJunction);
818 }
819
820 void AudioContext::removeMarkedSummingJunction(AudioSummingJunction* summingJunction)
821 {
822     ASSERT(isMainThread());
823     AutoLocker locker(*this);
824     m_dirtySummingJunctions.remove(summingJunction);
825 }
826
827 void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
828 {
829     ASSERT(isGraphOwner());    
830     m_dirtyAudioNodeOutputs.add(output);
831 }
832
833 void AudioContext::handleDirtyAudioSummingJunctions()
834 {
835     ASSERT(isGraphOwner());    
836
837     for (auto& junction : m_dirtySummingJunctions)
838         junction->updateRenderingState();
839
840     m_dirtySummingJunctions.clear();
841 }
842
843 void AudioContext::handleDirtyAudioNodeOutputs()
844 {
845     ASSERT(isGraphOwner());    
846
847     for (auto& output : m_dirtyAudioNodeOutputs)
848         output->updateRenderingState();
849
850     m_dirtyAudioNodeOutputs.clear();
851 }
852
853 void AudioContext::addAutomaticPullNode(AudioNode* node)
854 {
855     ASSERT(isGraphOwner());
856
857     if (m_automaticPullNodes.add(node).isNewEntry)
858         m_automaticPullNodesNeedUpdating = true;
859 }
860
861 void AudioContext::removeAutomaticPullNode(AudioNode* node)
862 {
863     ASSERT(isGraphOwner());
864
865     if (m_automaticPullNodes.remove(node))
866         m_automaticPullNodesNeedUpdating = true;
867 }
868
869 void AudioContext::updateAutomaticPullNodes()
870 {
871     ASSERT(isGraphOwner());
872
873     if (m_automaticPullNodesNeedUpdating) {
874         // Copy from m_automaticPullNodes to m_renderingAutomaticPullNodes.
875         m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
876
877         unsigned i = 0;
878         for (auto& output : m_automaticPullNodes)
879             m_renderingAutomaticPullNodes[i++] = output;
880
881         m_automaticPullNodesNeedUpdating = false;
882     }
883 }
884
885 void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
886 {
887     ASSERT(isAudioThread());
888
889     for (auto& node : m_renderingAutomaticPullNodes)
890         node->processIfNecessary(framesToProcess);
891 }
892
893 ScriptExecutionContext* AudioContext::scriptExecutionContext() const
894 {
895     return m_isStopScheduled ? 0 : ActiveDOMObject::scriptExecutionContext();
896 }
897
898 void AudioContext::nodeWillBeginPlayback()
899 {
900     // Called by scheduled AudioNodes when clients schedule their start times.
901     // Prior to the introduction of suspend(), resume(), and stop(), starting
902     // a scheduled AudioNode would remove the user-gesture restriction, if present,
903     // and would thus unmute the context. Now that AudioContext stays in the
904     // "suspended" state if a user-gesture restriction is present, starting a
905     // schedule AudioNode should set the state to "running", but only if the
906     // user-gesture restriction is set.
907     if (userGestureRequiredForAudioStart())
908         startRendering();
909 }
910
911 bool AudioContext::willBeginPlayback()
912 {
913     if (userGestureRequiredForAudioStart()) {
914         if (!ScriptController::processingUserGestureForMedia())
915             return false;
916         removeBehaviorRestriction(AudioContext::RequireUserGestureForAudioStartRestriction);
917     }
918
919     if (pageConsentRequiredForAudioStart()) {
920         Page* page = document()->page();
921         if (page && !page->canStartMedia()) {
922             document()->addMediaCanStartListener(this);
923             return false;
924         }
925         removeBehaviorRestriction(AudioContext::RequirePageConsentForAudioStartRestriction);
926     }
927
928     return m_mediaSession->clientWillBeginPlayback();
929 }
930
931 bool AudioContext::willPausePlayback()
932 {
933     if (userGestureRequiredForAudioStart()) {
934         if (!ScriptController::processingUserGestureForMedia())
935             return false;
936         removeBehaviorRestriction(AudioContext::RequireUserGestureForAudioStartRestriction);
937     }
938
939     if (pageConsentRequiredForAudioStart()) {
940         Page* page = document()->page();
941         if (page && !page->canStartMedia()) {
942             document()->addMediaCanStartListener(this);
943             return false;
944         }
945         removeBehaviorRestriction(AudioContext::RequirePageConsentForAudioStartRestriction);
946     }
947     
948     return m_mediaSession->clientWillPausePlayback();
949 }
950
951 void AudioContext::startRendering()
952 {
953     if (!willBeginPlayback())
954         return;
955
956     destination()->startRendering();
957     setState(State::Running);
958 }
959
960 void AudioContext::mediaCanStart(Document& document)
961 {
962     ASSERT_UNUSED(document, &document == this->document());
963     removeBehaviorRestriction(AudioContext::RequirePageConsentForAudioStartRestriction);
964     mayResumePlayback(true);
965 }
966
967 MediaProducer::MediaStateFlags AudioContext::mediaState() const
968 {
969     if (!m_isStopScheduled && m_destinationNode && m_destinationNode->isPlayingAudio())
970         return MediaProducer::IsPlayingAudio;
971
972     return MediaProducer::IsNotPlaying;
973 }
974
975 void AudioContext::pageMutedStateDidChange()
976 {
977     if (m_destinationNode && document()->page())
978         m_destinationNode->setMuted(document()->page()->isAudioMuted());
979 }
980
981 void AudioContext::isPlayingAudioDidChange()
982 {
983     // Make sure to call Document::updateIsPlayingMedia() on the main thread, since
984     // we could be on the audio I/O thread here and the call into WebCore could block.
985     callOnMainThread([protectedThis = makeRef(*this)] {
986         if (protectedThis->document())
987             protectedThis->document()->updateIsPlayingMedia();
988     });
989 }
990
991 void AudioContext::fireCompletionEvent()
992 {
993     ASSERT(isMainThread());
994     if (!isMainThread())
995         return;
996         
997     AudioBuffer* renderedBuffer = m_renderTarget.get();
998     setState(State::Closed);
999
1000     ASSERT(renderedBuffer);
1001     if (!renderedBuffer)
1002         return;
1003
1004     // Avoid firing the event if the document has already gone away.
1005     if (scriptExecutionContext()) {
1006         // Call the offline rendering completion event listener.
1007         m_eventQueue->enqueueEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
1008     }
1009 }
1010
1011 void AudioContext::incrementActiveSourceCount()
1012 {
1013     ++m_activeSourceCount;
1014 }
1015
1016 void AudioContext::decrementActiveSourceCount()
1017 {
1018     --m_activeSourceCount;
1019 }
1020
1021 void AudioContext::suspend(DOMPromise<void>&& promise)
1022 {
1023     if (isOfflineContext()) {
1024         promise.reject(INVALID_STATE_ERR);
1025         return;
1026     }
1027
1028     if (m_state == State::Suspended) {
1029         promise.resolve();
1030         return;
1031     }
1032
1033     if (m_state == State::Closed || m_state == State::Interrupted || !m_destinationNode) {
1034         promise.reject();
1035         return;
1036     }
1037
1038     addReaction(State::Suspended, WTFMove(promise));
1039
1040     if (!willPausePlayback())
1041         return;
1042
1043     lazyInitialize();
1044
1045     m_destinationNode->suspend([this, protectedThis = makeRef(*this)] {
1046         setState(State::Suspended);
1047     });
1048 }
1049
1050 void AudioContext::resume(DOMPromise<void>&& promise)
1051 {
1052     if (isOfflineContext()) {
1053         promise.reject(INVALID_STATE_ERR);
1054         return;
1055     }
1056
1057     if (m_state == State::Running) {
1058         promise.resolve();
1059         return;
1060     }
1061
1062     if (m_state == State::Closed || !m_destinationNode) {
1063         promise.reject();
1064         return;
1065     }
1066
1067     addReaction(State::Running, WTFMove(promise));
1068
1069     if (!willBeginPlayback())
1070         return;
1071
1072     lazyInitialize();
1073
1074     m_destinationNode->resume([this, protectedThis = makeRef(*this)] {
1075         setState(State::Running);
1076     });
1077 }
1078
1079 void AudioContext::close(DOMPromise<void>&& promise)
1080 {
1081     if (isOfflineContext()) {
1082         promise.reject(INVALID_STATE_ERR);
1083         return;
1084     }
1085
1086     if (m_state == State::Closed || !m_destinationNode) {
1087         promise.resolve();
1088         return;
1089     }
1090
1091     addReaction(State::Closed, WTFMove(promise));
1092
1093     lazyInitialize();
1094
1095     m_destinationNode->close([this, protectedThis = makeRef(*this)] {
1096         setState(State::Closed);
1097         uninitialize();
1098     });
1099 }
1100
1101
1102 void AudioContext::suspendPlayback()
1103 {
1104     if (!m_destinationNode || m_state == State::Closed)
1105         return;
1106
1107     if (m_state == State::Suspended) {
1108         if (m_mediaSession->state() == PlatformMediaSession::Interrupted)
1109             setState(State::Interrupted);
1110         return;
1111     }
1112
1113     lazyInitialize();
1114
1115     m_destinationNode->suspend([this, protectedThis = makeRef(*this)] {
1116         bool interrupted = m_mediaSession->state() == PlatformMediaSession::Interrupted;
1117         setState(interrupted ? State::Interrupted : State::Suspended);
1118     });
1119 }
1120
1121 void AudioContext::mayResumePlayback(bool shouldResume)
1122 {
1123     if (!m_destinationNode || m_state == State::Closed || m_state == State::Running)
1124         return;
1125
1126     if (!shouldResume) {
1127         setState(State::Suspended);
1128         return;
1129     }
1130
1131     if (!willBeginPlayback())
1132         return;
1133
1134     lazyInitialize();
1135
1136     m_destinationNode->resume([this, protectedThis = makeRef(*this)] {
1137         setState(State::Running);
1138     });
1139 }
1140
1141
1142 } // namespace WebCore
1143
1144 #endif // ENABLE(WEB_AUDIO)