1/*
2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26
27#if ENABLE(WEB_AUDIO)
28
29#include "modules/webaudio/AudioContext.h"
30
31#include "bindings/v8/ExceptionMessages.h"
32#include "bindings/v8/ExceptionState.h"
33#include "core/dom/Document.h"
34#include "core/dom/ExceptionCode.h"
35#include "core/html/HTMLMediaElement.h"
36#include "core/inspector/ScriptCallStack.h"
37#include "platform/audio/FFTFrame.h"
38#include "platform/audio/HRTFPanner.h"
39#include "modules/mediastream/MediaStream.h"
40#include "modules/webaudio/AnalyserNode.h"
41#include "modules/webaudio/AudioBuffer.h"
42#include "modules/webaudio/AudioBufferCallback.h"
43#include "modules/webaudio/AudioBufferSourceNode.h"
44#include "modules/webaudio/AudioListener.h"
45#include "modules/webaudio/AudioNodeInput.h"
46#include "modules/webaudio/AudioNodeOutput.h"
47#include "modules/webaudio/BiquadFilterNode.h"
48#include "modules/webaudio/ChannelMergerNode.h"
49#include "modules/webaudio/ChannelSplitterNode.h"
50#include "modules/webaudio/ConvolverNode.h"
51#include "modules/webaudio/DefaultAudioDestinationNode.h"
52#include "modules/webaudio/DelayNode.h"
53#include "modules/webaudio/DynamicsCompressorNode.h"
54#include "modules/webaudio/GainNode.h"
55#include "modules/webaudio/MediaElementAudioSourceNode.h"
56#include "modules/webaudio/MediaStreamAudioDestinationNode.h"
57#include "modules/webaudio/MediaStreamAudioSourceNode.h"
58#include "modules/webaudio/OfflineAudioCompletionEvent.h"
59#include "modules/webaudio/OfflineAudioContext.h"
60#include "modules/webaudio/OfflineAudioDestinationNode.h"
61#include "modules/webaudio/OscillatorNode.h"
62#include "modules/webaudio/PannerNode.h"
63#include "modules/webaudio/PeriodicWave.h"
64#include "modules/webaudio/ScriptProcessorNode.h"
65#include "modules/webaudio/WaveShaperNode.h"
66
67#if DEBUG_AUDIONODE_REFERENCES
68#include <stdio.h>
69#endif
70
71#include "wtf/ArrayBuffer.h"
72#include "wtf/Atomics.h"
73#include "wtf/PassOwnPtr.h"
74#include "wtf/text/WTFString.h"
75
76// FIXME: check the proper way to reference an undefined thread ID
77const int UndefinedThreadIdentifier = 0xffffffff;
78
79namespace WebCore {
80
81bool AudioContext::isSampleRateRangeGood(float sampleRate)
82{
83    // FIXME: It would be nice if the minimum sample-rate could be less than 44.1KHz,
84    // but that will require some fixes in HRTFPanner::fftSizeForSampleRate(), and some testing there.
85    return sampleRate >= 44100 && sampleRate <= 96000;
86}
87
88// Don't allow more than this number of simultaneous AudioContexts talking to hardware.
89const unsigned MaxHardwareContexts = 4;
90unsigned AudioContext::s_hardwareContextCount = 0;
91
92PassRefPtr<AudioContext> AudioContext::create(Document& document, ExceptionState& exceptionState)
93{
94    ASSERT(isMainThread());
95    if (s_hardwareContextCount >= MaxHardwareContexts) {
96        exceptionState.throwDOMException(
97            SyntaxError,
98            "number of hardware contexts reached maximum (" + String::number(MaxHardwareContexts) + ").");
99        return 0;
100    }
101
102    RefPtr<AudioContext> audioContext(adoptRef(new AudioContext(&document)));
103    audioContext->suspendIfNeeded();
104    return audioContext.release();
105}
106
107PassRefPtr<AudioContext> AudioContext::create(Document& document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
108{
109    document.addConsoleMessage(JSMessageSource, WarningMessageLevel, "Deprecated AudioContext constructor: use OfflineAudioContext instead");
110    return OfflineAudioContext::create(&document, numberOfChannels, numberOfFrames, sampleRate, exceptionState);
111}
112
113// Constructor for rendering to the audio hardware.
114AudioContext::AudioContext(Document* document)
115    : ActiveDOMObject(document)
116    , m_isStopScheduled(false)
117    , m_isInitialized(false)
118    , m_isAudioThreadFinished(false)
119    , m_destinationNode(0)
120    , m_isDeletionScheduled(false)
121    , m_automaticPullNodesNeedUpdating(false)
122    , m_connectionCount(0)
123    , m_audioThread(0)
124    , m_graphOwnerThread(UndefinedThreadIdentifier)
125    , m_isOfflineContext(false)
126    , m_activeSourceCount(0)
127{
128    constructCommon();
129
130    m_destinationNode = DefaultAudioDestinationNode::create(this);
131
132    // This sets in motion an asynchronous loading mechanism on another thread.
133    // We can check m_hrtfDatabaseLoader->isLoaded() to find out whether or not it has been fully loaded.
134    // It's not that useful to have a callback function for this since the audio thread automatically starts rendering on the graph
135    // when this has finished (see AudioDestinationNode).
136    m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate());
137}
138
139// Constructor for offline (non-realtime) rendering.
140AudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
141    : ActiveDOMObject(document)
142    , m_isStopScheduled(false)
143    , m_isInitialized(false)
144    , m_isAudioThreadFinished(false)
145    , m_destinationNode(0)
146    , m_automaticPullNodesNeedUpdating(false)
147    , m_connectionCount(0)
148    , m_audioThread(0)
149    , m_graphOwnerThread(UndefinedThreadIdentifier)
150    , m_isOfflineContext(true)
151    , m_activeSourceCount(0)
152{
153    constructCommon();
154
155    m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(sampleRate);
156
157    // Create a new destination for offline rendering.
158    m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
159    ASSERT(m_renderTarget);
160    m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());
161    ASSERT(m_destinationNode);
162}
163
164void AudioContext::constructCommon()
165{
166    ScriptWrappable::init(this);
167    // According to spec AudioContext must die only after page navigate.
168    // Lets mark it as ActiveDOMObject with pending activity and unmark it in clear method.
169    setPendingActivity(this);
170
171    FFTFrame::initialize();
172
173    m_listener = AudioListener::create();
174}
175
176AudioContext::~AudioContext()
177{
178#if DEBUG_AUDIONODE_REFERENCES
179    fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this);
180#endif
181    // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
182    ASSERT(!m_isInitialized);
183    ASSERT(m_isStopScheduled);
184    ASSERT(!m_nodesToDelete.size());
185    ASSERT(!m_referencedNodes.size());
186    ASSERT(!m_finishedNodes.size());
187    ASSERT(!m_automaticPullNodes.size());
188    if (m_automaticPullNodesNeedUpdating)
189        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
190    ASSERT(!m_renderingAutomaticPullNodes.size());
191}
192
193void AudioContext::lazyInitialize()
194{
195    if (!m_isInitialized) {
196        // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
197        ASSERT(!m_isAudioThreadFinished);
198        if (!m_isAudioThreadFinished) {
199            if (m_destinationNode.get()) {
200                m_destinationNode->initialize();
201
202                if (!isOfflineContext()) {
203                    // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
204                    // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
205                    // NOTE: for now default AudioContext does not need an explicit startRendering() call from JavaScript.
206                    // We may want to consider requiring it for symmetry with OfflineAudioContext.
207                    m_destinationNode->startRendering();
208                    ++s_hardwareContextCount;
209                }
210
211            }
212            m_isInitialized = true;
213        }
214    }
215}
216
217void AudioContext::clear()
218{
219    // 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.
220    if (m_destinationNode)
221        m_destinationNode.clear();
222
223    // Audio thread is dead. Nobody will schedule node deletion action. Let's do it ourselves.
224    do {
225        deleteMarkedNodes();
226        m_nodesToDelete.append(m_nodesMarkedForDeletion);
227        m_nodesMarkedForDeletion.clear();
228    } while (m_nodesToDelete.size());
229
230    // It was set in constructCommon.
231    unsetPendingActivity(this);
232}
233
234void AudioContext::uninitialize()
235{
236    ASSERT(isMainThread());
237
238    if (!m_isInitialized)
239        return;
240
241    // This stops the audio thread and all audio rendering.
242    m_destinationNode->uninitialize();
243
244    // Don't allow the context to initialize a second time after it's already been explicitly uninitialized.
245    m_isAudioThreadFinished = true;
246
247    if (!isOfflineContext()) {
248        ASSERT(s_hardwareContextCount);
249        --s_hardwareContextCount;
250    }
251
252    // Get rid of the sources which may still be playing.
253    derefUnfinishedSourceNodes();
254
255    m_isInitialized = false;
256}
257
258bool AudioContext::isInitialized() const
259{
260    return m_isInitialized;
261}
262
263bool AudioContext::isRunnable() const
264{
265    if (!isInitialized())
266        return false;
267
268    // Check with the HRTF spatialization system to see if it's finished loading.
269    return m_hrtfDatabaseLoader->isLoaded();
270}
271
272void AudioContext::stopDispatch(void* userData)
273{
274    AudioContext* context = reinterpret_cast<AudioContext*>(userData);
275    ASSERT(context);
276    if (!context)
277        return;
278
279    context->uninitialize();
280    context->clear();
281}
282
283void AudioContext::stop()
284{
285    // Usually ExecutionContext calls stop twice.
286    if (m_isStopScheduled)
287        return;
288    m_isStopScheduled = true;
289
290    // Don't call uninitialize() immediately here because the ExecutionContext is in the middle
291    // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
292    // ActiveDOMObjects so let's schedule uninitialize() to be called later.
293    // FIXME: see if there's a more direct way to handle this issue.
294    callOnMainThread(stopDispatch, this);
295}
296
297PassRefPtr<AudioBuffer> AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
298{
299    RefPtr<AudioBuffer> audioBuffer = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
300    if (!audioBuffer.get()) {
301        if (numberOfChannels > AudioContext::maxNumberOfChannels()) {
302            exceptionState.throwDOMException(
303                NotSupportedError,
304                "requested number of channels (" + String::number(numberOfChannels) + ") exceeds maximum (" + String::number(AudioContext::maxNumberOfChannels()) + ")");
305        } else if (sampleRate < AudioBuffer::minAllowedSampleRate() || sampleRate > AudioBuffer::maxAllowedSampleRate()) {
306            exceptionState.throwDOMException(
307                NotSupportedError,
308                "requested sample rate (" + String::number(sampleRate)
309                + ") does not lie in the allowed range of "
310                + String::number(AudioBuffer::minAllowedSampleRate())
311                + "-" + String::number(AudioBuffer::maxAllowedSampleRate()) + " Hz");
312        } else if (!numberOfFrames) {
313            exceptionState.throwDOMException(
314                NotSupportedError,
315                "number of frames must be greater than 0.");
316        } else {
317            exceptionState.throwDOMException(
318                NotSupportedError,
319                "unable to create buffer of " + String::number(numberOfChannels)
320                + " channel(s) of " + String::number(numberOfFrames)
321                + " frames each.");
322        }
323        return 0;
324    }
325
326    return audioBuffer;
327}
328
329PassRefPtr<AudioBuffer> AudioContext::createBuffer(ArrayBuffer* arrayBuffer, bool mixToMono, ExceptionState& exceptionState)
330{
331    ASSERT(arrayBuffer);
332    if (!arrayBuffer) {
333        exceptionState.throwDOMException(
334            SyntaxError,
335            "invalid ArrayBuffer.");
336        return 0;
337    }
338
339    RefPtr<AudioBuffer> audioBuffer = AudioBuffer::createFromAudioFileData(arrayBuffer->data(), arrayBuffer->byteLength(), mixToMono, sampleRate());
340    if (!audioBuffer.get()) {
341        exceptionState.throwDOMException(
342            SyntaxError,
343            "invalid audio data in ArrayBuffer.");
344        return 0;
345    }
346
347    return audioBuffer;
348}
349
350void AudioContext::decodeAudioData(ArrayBuffer* audioData, PassOwnPtr<AudioBufferCallback> successCallback, PassOwnPtr<AudioBufferCallback> errorCallback, ExceptionState& exceptionState)
351{
352    if (!audioData) {
353        exceptionState.throwDOMException(
354            SyntaxError,
355            "invalid ArrayBuffer for audioData.");
356        return;
357    }
358    m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback);
359}
360
361PassRefPtr<AudioBufferSourceNode> AudioContext::createBufferSource()
362{
363    ASSERT(isMainThread());
364    lazyInitialize();
365    RefPtr<AudioBufferSourceNode> node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
366
367    // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
368    // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
369    refNode(node.get());
370
371    return node;
372}
373
374PassRefPtr<MediaElementAudioSourceNode> AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState)
375{
376    if (!mediaElement) {
377        exceptionState.throwDOMException(
378            InvalidStateError,
379            "invalid HTMLMedialElement.");
380        return 0;
381    }
382
383    ASSERT(isMainThread());
384    lazyInitialize();
385
386    // First check if this media element already has a source node.
387    if (mediaElement->audioSourceNode()) {
388        exceptionState.throwDOMException(
389            InvalidStateError,
390            "invalid HTMLMediaElement.");
391        return 0;
392    }
393
394    RefPtr<MediaElementAudioSourceNode> node = MediaElementAudioSourceNode::create(this, mediaElement);
395
396    mediaElement->setAudioSourceNode(node.get());
397
398    refNode(node.get()); // context keeps reference until node is disconnected
399    return node;
400}
401
402PassRefPtr<MediaStreamAudioSourceNode> AudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState)
403{
404    if (!mediaStream) {
405        exceptionState.throwDOMException(
406            InvalidStateError,
407            "invalid MediaStream source");
408        return 0;
409    }
410
411    ASSERT(isMainThread());
412    lazyInitialize();
413
414    AudioSourceProvider* provider = 0;
415
416    MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks();
417    RefPtr<MediaStreamTrack> audioTrack;
418
419    // FIXME: get a provider for non-local MediaStreams (like from a remote peer).
420    for (size_t i = 0; i < audioTracks.size(); ++i) {
421        audioTrack = audioTracks[i];
422        if (audioTrack->component()->audioSourceProvider()) {
423            provider = audioTrack->component()->audioSourceProvider();
424            break;
425        }
426    }
427
428    RefPtr<MediaStreamAudioSourceNode> node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack.get(), provider);
429
430    // FIXME: Only stereo streams are supported right now. We should be able to accept multi-channel streams.
431    node->setFormat(2, sampleRate());
432
433    refNode(node.get()); // context keeps reference until node is disconnected
434    return node;
435}
436
437PassRefPtr<MediaStreamAudioDestinationNode> AudioContext::createMediaStreamDestination()
438{
439    // FIXME: Add support for an optional argument which specifies the number of channels.
440    // FIXME: The default should probably be stereo instead of mono.
441    return MediaStreamAudioDestinationNode::create(this, 1);
442}
443
444PassRefPtr<ScriptProcessorNode> AudioContext::createScriptProcessor(ExceptionState& exceptionState)
445{
446    // Set number of input/output channels to stereo by default.
447    return createScriptProcessor(0, 2, 2, exceptionState);
448}
449
450PassRefPtr<ScriptProcessorNode> AudioContext::createScriptProcessor(size_t bufferSize, ExceptionState& exceptionState)
451{
452    // Set number of input/output channels to stereo by default.
453    return createScriptProcessor(bufferSize, 2, 2, exceptionState);
454}
455
456PassRefPtr<ScriptProcessorNode> AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState& exceptionState)
457{
458    // Set number of output channels to stereo by default.
459    return createScriptProcessor(bufferSize, numberOfInputChannels, 2, exceptionState);
460}
461
462PassRefPtr<ScriptProcessorNode> AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState)
463{
464    ASSERT(isMainThread());
465    lazyInitialize();
466    RefPtr<ScriptProcessorNode> node = ScriptProcessorNode::create(this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
467
468    if (!node.get()) {
469        if (!numberOfInputChannels && !numberOfOutputChannels) {
470            exceptionState.throwDOMException(
471                IndexSizeError,
472                "number of input channels and output channels cannot both be zero.");
473        } else if (numberOfInputChannels > AudioContext::maxNumberOfChannels()) {
474            exceptionState.throwDOMException(
475                IndexSizeError,
476                "number of input channels (" + String::number(numberOfInputChannels)
477                + ") exceeds maximum ("
478                + String::number(AudioContext::maxNumberOfChannels()) + ").");
479        } else if (numberOfOutputChannels > AudioContext::maxNumberOfChannels()) {
480            exceptionState.throwDOMException(
481                IndexSizeError,
482                "number of output channels (" + String::number(numberOfInputChannels)
483                + ") exceeds maximum ("
484                + String::number(AudioContext::maxNumberOfChannels()) + ").");
485        } else {
486            exceptionState.throwDOMException(
487                IndexSizeError,
488                "buffer size (" + String::number(bufferSize)
489                + ") must be a power of two between 256 and 16384.");
490        }
491        return 0;
492    }
493
494    refNode(node.get()); // context keeps reference until we stop making javascript rendering callbacks
495    return node;
496}
497
498PassRefPtr<BiquadFilterNode> AudioContext::createBiquadFilter()
499{
500    ASSERT(isMainThread());
501    lazyInitialize();
502    return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
503}
504
505PassRefPtr<WaveShaperNode> AudioContext::createWaveShaper()
506{
507    ASSERT(isMainThread());
508    lazyInitialize();
509    return WaveShaperNode::create(this);
510}
511
512PassRefPtr<PannerNode> AudioContext::createPanner()
513{
514    ASSERT(isMainThread());
515    lazyInitialize();
516    return PannerNode::create(this, m_destinationNode->sampleRate());
517}
518
519PassRefPtr<ConvolverNode> AudioContext::createConvolver()
520{
521    ASSERT(isMainThread());
522    lazyInitialize();
523    return ConvolverNode::create(this, m_destinationNode->sampleRate());
524}
525
526PassRefPtr<DynamicsCompressorNode> AudioContext::createDynamicsCompressor()
527{
528    ASSERT(isMainThread());
529    lazyInitialize();
530    return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
531}
532
533PassRefPtr<AnalyserNode> AudioContext::createAnalyser()
534{
535    ASSERT(isMainThread());
536    lazyInitialize();
537    return AnalyserNode::create(this, m_destinationNode->sampleRate());
538}
539
540PassRefPtr<GainNode> AudioContext::createGain()
541{
542    ASSERT(isMainThread());
543    lazyInitialize();
544    return GainNode::create(this, m_destinationNode->sampleRate());
545}
546
547PassRefPtr<DelayNode> AudioContext::createDelay(ExceptionState& exceptionState)
548{
549    const double defaultMaxDelayTime = 1;
550    return createDelay(defaultMaxDelayTime, exceptionState);
551}
552
553PassRefPtr<DelayNode> AudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState)
554{
555    ASSERT(isMainThread());
556    lazyInitialize();
557    RefPtr<DelayNode> node = DelayNode::create(this, m_destinationNode->sampleRate(), maxDelayTime, exceptionState);
558    if (exceptionState.hadException())
559        return 0;
560    return node;
561}
562
563PassRefPtr<ChannelSplitterNode> AudioContext::createChannelSplitter(ExceptionState& exceptionState)
564{
565    const unsigned ChannelSplitterDefaultNumberOfOutputs = 6;
566    return createChannelSplitter(ChannelSplitterDefaultNumberOfOutputs, exceptionState);
567}
568
569PassRefPtr<ChannelSplitterNode> AudioContext::createChannelSplitter(size_t numberOfOutputs, ExceptionState& exceptionState)
570{
571    ASSERT(isMainThread());
572    lazyInitialize();
573
574    RefPtr<ChannelSplitterNode> node = ChannelSplitterNode::create(this, m_destinationNode->sampleRate(), numberOfOutputs);
575
576    if (!node.get()) {
577        exceptionState.throwDOMException(
578            IndexSizeError,
579            "number of outputs (" + String::number(numberOfOutputs)
580            + ") must be between 1 and "
581            + String::number(AudioContext::maxNumberOfChannels()) + ".");
582        return 0;
583    }
584
585    return node;
586}
587
588PassRefPtr<ChannelMergerNode> AudioContext::createChannelMerger(ExceptionState& exceptionState)
589{
590    const unsigned ChannelMergerDefaultNumberOfInputs = 6;
591    return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionState);
592}
593
594PassRefPtr<ChannelMergerNode> AudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState)
595{
596    ASSERT(isMainThread());
597    lazyInitialize();
598
599    RefPtr<ChannelMergerNode> node = ChannelMergerNode::create(this, m_destinationNode->sampleRate(), numberOfInputs);
600
601    if (!node.get()) {
602        exceptionState.throwDOMException(
603            IndexSizeError,
604            "number of inputs (" + String::number(numberOfInputs)
605            + ") must be between 1 and "
606            + String::number(AudioContext::maxNumberOfChannels()) + ".");
607        return 0;
608    }
609
610    return node;
611}
612
613PassRefPtr<OscillatorNode> AudioContext::createOscillator()
614{
615    ASSERT(isMainThread());
616    lazyInitialize();
617
618    RefPtr<OscillatorNode> node = OscillatorNode::create(this, m_destinationNode->sampleRate());
619
620    // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
621    // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
622    refNode(node.get());
623
624    return node;
625}
626
627PassRefPtr<PeriodicWave> AudioContext::createPeriodicWave(Float32Array* real, Float32Array* imag, ExceptionState& exceptionState)
628{
629    ASSERT(isMainThread());
630
631    if (!real) {
632        exceptionState.throwDOMException(
633            SyntaxError,
634            "invalid real array");
635        return 0;
636    }
637
638    if (!imag) {
639        exceptionState.throwDOMException(
640            SyntaxError,
641            "invalid imaginary array");
642        return 0;
643    }
644
645    if (real->length() != imag->length()) {
646        exceptionState.throwDOMException(
647            IndexSizeError,
648            "length of real array (" + String::number(real->length())
649            + ") and length of imaginary array (" +  String::number(imag->length())
650            + ") must match.");
651        return 0;
652    }
653
654    if (real->length() > 4096) {
655        exceptionState.throwDOMException(
656            IndexSizeError,
657            "length of real array (" + String::number(real->length())
658            + ") exceeds allowed maximum of 4096");
659        return 0;
660    }
661
662    if (imag->length() > 4096) {
663        exceptionState.throwDOMException(
664            IndexSizeError,
665            "length of imaginary array (" + String::number(imag->length())
666            + ") exceeds allowed maximum of 4096");
667        return 0;
668    }
669
670    lazyInitialize();
671    return PeriodicWave::create(sampleRate(), real, imag);
672}
673
674void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
675{
676    ASSERT(isAudioThread());
677    m_finishedNodes.append(node);
678}
679
680void AudioContext::derefFinishedSourceNodes()
681{
682    ASSERT(isGraphOwner());
683    ASSERT(isAudioThread() || isAudioThreadFinished());
684    for (unsigned i = 0; i < m_finishedNodes.size(); i++)
685        derefNode(m_finishedNodes[i]);
686
687    m_finishedNodes.clear();
688}
689
690void AudioContext::refNode(AudioNode* node)
691{
692    ASSERT(isMainThread());
693    AutoLocker locker(this);
694
695    node->ref(AudioNode::RefTypeConnection);
696    m_referencedNodes.append(node);
697}
698
699void AudioContext::derefNode(AudioNode* node)
700{
701    ASSERT(isGraphOwner());
702
703    node->deref(AudioNode::RefTypeConnection);
704
705    for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
706        if (node == m_referencedNodes[i]) {
707            m_referencedNodes.remove(i);
708            break;
709        }
710    }
711}
712
713void AudioContext::derefUnfinishedSourceNodes()
714{
715    ASSERT(isMainThread() && isAudioThreadFinished());
716    for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
717        m_referencedNodes[i]->deref(AudioNode::RefTypeConnection);
718
719    m_referencedNodes.clear();
720}
721
722void AudioContext::lock(bool& mustReleaseLock)
723{
724    // Don't allow regular lock in real-time audio thread.
725    ASSERT(isMainThread());
726
727    ThreadIdentifier thisThread = currentThread();
728
729    if (thisThread == m_graphOwnerThread) {
730        // We already have the lock.
731        mustReleaseLock = false;
732    } else {
733        // Acquire the lock.
734        m_contextGraphMutex.lock();
735        m_graphOwnerThread = thisThread;
736        mustReleaseLock = true;
737    }
738}
739
740bool AudioContext::tryLock(bool& mustReleaseLock)
741{
742    ThreadIdentifier thisThread = currentThread();
743    bool isAudioThread = thisThread == audioThread();
744
745    // Try to catch cases of using try lock on main thread - it should use regular lock.
746    ASSERT(isAudioThread || isAudioThreadFinished());
747
748    if (!isAudioThread) {
749        // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
750        lock(mustReleaseLock);
751        return true;
752    }
753
754    bool hasLock;
755
756    if (thisThread == m_graphOwnerThread) {
757        // Thread already has the lock.
758        hasLock = true;
759        mustReleaseLock = false;
760    } else {
761        // Don't already have the lock - try to acquire it.
762        hasLock = m_contextGraphMutex.tryLock();
763
764        if (hasLock)
765            m_graphOwnerThread = thisThread;
766
767        mustReleaseLock = hasLock;
768    }
769
770    return hasLock;
771}
772
773void AudioContext::unlock()
774{
775    ASSERT(currentThread() == m_graphOwnerThread);
776
777    m_graphOwnerThread = UndefinedThreadIdentifier;
778    m_contextGraphMutex.unlock();
779}
780
781bool AudioContext::isAudioThread() const
782{
783    return currentThread() == m_audioThread;
784}
785
786bool AudioContext::isGraphOwner() const
787{
788    return currentThread() == m_graphOwnerThread;
789}
790
791void AudioContext::addDeferredFinishDeref(AudioNode* node)
792{
793    ASSERT(isAudioThread());
794    m_deferredFinishDerefList.append(node);
795}
796
797void AudioContext::handlePreRenderTasks()
798{
799    ASSERT(isAudioThread());
800
801    // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
802    // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
803    bool mustReleaseLock;
804    if (tryLock(mustReleaseLock)) {
805        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
806        handleDirtyAudioSummingJunctions();
807        handleDirtyAudioNodeOutputs();
808
809        updateAutomaticPullNodes();
810
811        if (mustReleaseLock)
812            unlock();
813    }
814}
815
816void AudioContext::handlePostRenderTasks()
817{
818    ASSERT(isAudioThread());
819
820    // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
821    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
822    // from the render graph (in which case they'll render silence).
823    bool mustReleaseLock;
824    if (tryLock(mustReleaseLock)) {
825        // Take care of finishing any derefs where the tryLock() failed previously.
826        handleDeferredFinishDerefs();
827
828        // Dynamically clean up nodes which are no longer needed.
829        derefFinishedSourceNodes();
830
831        // Don't delete in the real-time thread. Let the main thread do it.
832        // Ref-counted objects held by certain AudioNodes may not be thread-safe.
833        scheduleNodeDeletion();
834
835        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
836        handleDirtyAudioSummingJunctions();
837        handleDirtyAudioNodeOutputs();
838
839        updateAutomaticPullNodes();
840
841        if (mustReleaseLock)
842            unlock();
843    }
844}
845
846void AudioContext::handleDeferredFinishDerefs()
847{
848    ASSERT(isAudioThread() && isGraphOwner());
849    for (unsigned i = 0; i < m_deferredFinishDerefList.size(); ++i) {
850        AudioNode* node = m_deferredFinishDerefList[i];
851        node->finishDeref(AudioNode::RefTypeConnection);
852    }
853
854    m_deferredFinishDerefList.clear();
855}
856
857void AudioContext::markForDeletion(AudioNode* node)
858{
859    ASSERT(isGraphOwner());
860
861    if (isAudioThreadFinished())
862        m_nodesToDelete.append(node);
863    else
864        m_nodesMarkedForDeletion.append(node);
865
866    // This is probably the best time for us to remove the node from automatic pull list,
867    // since all connections are gone and we hold the graph lock. Then when handlePostRenderTasks()
868    // gets a chance to schedule the deletion work, updateAutomaticPullNodes() also gets a chance to
869    // modify m_renderingAutomaticPullNodes.
870    removeAutomaticPullNode(node);
871}
872
873void AudioContext::scheduleNodeDeletion()
874{
875    bool isGood = m_isInitialized && isGraphOwner();
876    ASSERT(isGood);
877    if (!isGood)
878        return;
879
880    // Make sure to call deleteMarkedNodes() on main thread.
881    if (m_nodesMarkedForDeletion.size() && !m_isDeletionScheduled) {
882        m_nodesToDelete.append(m_nodesMarkedForDeletion);
883        m_nodesMarkedForDeletion.clear();
884
885        m_isDeletionScheduled = true;
886
887        // Don't let ourself get deleted before the callback.
888        // See matching deref() in deleteMarkedNodesDispatch().
889        ref();
890        callOnMainThread(deleteMarkedNodesDispatch, this);
891    }
892}
893
894void AudioContext::deleteMarkedNodesDispatch(void* userData)
895{
896    AudioContext* context = reinterpret_cast<AudioContext*>(userData);
897    ASSERT(context);
898    if (!context)
899        return;
900
901    context->deleteMarkedNodes();
902    context->deref();
903}
904
905void AudioContext::deleteMarkedNodes()
906{
907    ASSERT(isMainThread());
908
909    // Protect this object from being deleted before we release the mutex locked by AutoLocker.
910    RefPtr<AudioContext> protect(this);
911    {
912        AutoLocker locker(this);
913
914        while (size_t n = m_nodesToDelete.size()) {
915            AudioNode* node = m_nodesToDelete[n - 1];
916            m_nodesToDelete.removeLast();
917
918            // Before deleting the node, clear out any AudioNodeInputs from m_dirtySummingJunctions.
919            unsigned numberOfInputs = node->numberOfInputs();
920            for (unsigned i = 0; i < numberOfInputs; ++i)
921                m_dirtySummingJunctions.remove(node->input(i));
922
923            // Before deleting the node, clear out any AudioNodeOutputs from m_dirtyAudioNodeOutputs.
924            unsigned numberOfOutputs = node->numberOfOutputs();
925            for (unsigned i = 0; i < numberOfOutputs; ++i)
926                m_dirtyAudioNodeOutputs.remove(node->output(i));
927
928            // Finally, delete it.
929            delete node;
930        }
931        m_isDeletionScheduled = false;
932    }
933}
934
935void AudioContext::markSummingJunctionDirty(AudioSummingJunction* summingJunction)
936{
937    ASSERT(isGraphOwner());
938    m_dirtySummingJunctions.add(summingJunction);
939}
940
941void AudioContext::removeMarkedSummingJunction(AudioSummingJunction* summingJunction)
942{
943    ASSERT(isMainThread());
944    AutoLocker locker(this);
945    m_dirtySummingJunctions.remove(summingJunction);
946}
947
948void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
949{
950    ASSERT(isGraphOwner());
951    m_dirtyAudioNodeOutputs.add(output);
952}
953
954void AudioContext::handleDirtyAudioSummingJunctions()
955{
956    ASSERT(isGraphOwner());
957
958    for (HashSet<AudioSummingJunction*>::iterator i = m_dirtySummingJunctions.begin(); i != m_dirtySummingJunctions.end(); ++i)
959        (*i)->updateRenderingState();
960
961    m_dirtySummingJunctions.clear();
962}
963
964void AudioContext::handleDirtyAudioNodeOutputs()
965{
966    ASSERT(isGraphOwner());
967
968    for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
969        (*i)->updateRenderingState();
970
971    m_dirtyAudioNodeOutputs.clear();
972}
973
974void AudioContext::addAutomaticPullNode(AudioNode* node)
975{
976    ASSERT(isGraphOwner());
977
978    if (!m_automaticPullNodes.contains(node)) {
979        m_automaticPullNodes.add(node);
980        m_automaticPullNodesNeedUpdating = true;
981    }
982}
983
984void AudioContext::removeAutomaticPullNode(AudioNode* node)
985{
986    ASSERT(isGraphOwner());
987
988    if (m_automaticPullNodes.contains(node)) {
989        m_automaticPullNodes.remove(node);
990        m_automaticPullNodesNeedUpdating = true;
991    }
992}
993
994void AudioContext::updateAutomaticPullNodes()
995{
996    ASSERT(isGraphOwner());
997
998    if (m_automaticPullNodesNeedUpdating) {
999        // Copy from m_automaticPullNodes to m_renderingAutomaticPullNodes.
1000        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
1001
1002        unsigned j = 0;
1003        for (HashSet<AudioNode*>::iterator i = m_automaticPullNodes.begin(); i != m_automaticPullNodes.end(); ++i, ++j) {
1004            AudioNode* output = *i;
1005            m_renderingAutomaticPullNodes[j] = output;
1006        }
1007
1008        m_automaticPullNodesNeedUpdating = false;
1009    }
1010}
1011
1012void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
1013{
1014    ASSERT(isAudioThread());
1015
1016    for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i)
1017        m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess);
1018}
1019
1020const AtomicString& AudioContext::interfaceName() const
1021{
1022    return EventTargetNames::AudioContext;
1023}
1024
1025ExecutionContext* AudioContext::executionContext() const
1026{
1027    return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext();
1028}
1029
1030void AudioContext::startRendering()
1031{
1032    destination()->startRendering();
1033}
1034
1035void AudioContext::fireCompletionEvent()
1036{
1037    ASSERT(isMainThread());
1038    if (!isMainThread())
1039        return;
1040
1041    AudioBuffer* renderedBuffer = m_renderTarget.get();
1042
1043    ASSERT(renderedBuffer);
1044    if (!renderedBuffer)
1045        return;
1046
1047    // Avoid firing the event if the document has already gone away.
1048    if (executionContext()) {
1049        // Call the offline rendering completion event listener.
1050        dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
1051    }
1052}
1053
1054void AudioContext::incrementActiveSourceCount()
1055{
1056    atomicIncrement(&m_activeSourceCount);
1057}
1058
1059void AudioContext::decrementActiveSourceCount()
1060{
1061    atomicDecrement(&m_activeSourceCount);
1062}
1063
1064} // namespace WebCore
1065
1066#endif // ENABLE(WEB_AUDIO)
1067