1d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu/*
2d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * Copyright (C) 2010, Google Inc. All rights reserved.
3d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu *
4d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * Redistribution and use in source and binary forms, with or without
5d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * modification, are permitted provided that the following conditions
6d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * are met:
7d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * 1.  Redistributions of source code must retain the above copyright
8d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu *    notice, this list of conditions and the following disclaimer.
9d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * 2.  Redistributions in binary form must reproduce the above copyright
10d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu *    notice, this list of conditions and the following disclaimer in the
11d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu *    documentation and/or other materials provided with the distribution.
12d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu *
13d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu */
24d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
25d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "config.h"
26d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
27d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#if ENABLE(WEB_AUDIO)
28d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
29d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioContext.h"
30d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
31d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "bindings/core/v8/ExceptionMessages.h"
32d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "bindings/core/v8/ExceptionState.h"
33d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "core/dom/Document.h"
34d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "core/dom/ExceptionCode.h"
35d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "core/html/HTMLMediaElement.h"
36d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "core/inspector/ScriptCallStack.h"
37d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "platform/audio/FFTFrame.h"
38d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "platform/audio/HRTFPanner.h"
39d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/mediastream/MediaStream.h"
40d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AnalyserNode.h"
41d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioBuffer.h"
42d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioBufferCallback.h"
43d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioBufferSourceNode.h"
44d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioListener.h"
45d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioNodeInput.h"
46d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/AudioNodeOutput.h"
47d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/BiquadFilterNode.h"
48d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/ChannelMergerNode.h"
49d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/ChannelSplitterNode.h"
50d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/ConvolverNode.h"
51d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/DefaultAudioDestinationNode.h"
52d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/DelayNode.h"
53d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/DynamicsCompressorNode.h"
54d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/GainNode.h"
55d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/MediaElementAudioSourceNode.h"
56d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/MediaStreamAudioDestinationNode.h"
57d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#include "modules/webaudio/MediaStreamAudioSourceNode.h"
584531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/OfflineAudioCompletionEvent.h"
594531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/OfflineAudioContext.h"
604531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/OfflineAudioDestinationNode.h"
614531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/OscillatorNode.h"
624531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/PannerNode.h"
634531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/PeriodicWave.h"
644531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/ScriptProcessorNode.h"
654531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "modules/webaudio/WaveShaperNode.h"
664531356817ec8383ac35932903773de67af92e37Chia-I Wu
674531356817ec8383ac35932903773de67af92e37Chia-I Wu#if DEBUG_AUDIONODE_REFERENCES
684531356817ec8383ac35932903773de67af92e37Chia-I Wu#include <stdio.h>
694531356817ec8383ac35932903773de67af92e37Chia-I Wu#endif
704531356817ec8383ac35932903773de67af92e37Chia-I Wu
714531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "wtf/ArrayBuffer.h"
724531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "wtf/Atomics.h"
734531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "wtf/PassOwnPtr.h"
744531356817ec8383ac35932903773de67af92e37Chia-I Wu#include "wtf/text/WTFString.h"
75d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
76d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu// FIXME: check the proper way to reference an undefined thread ID
77d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuconst WTF::ThreadIdentifier UndefinedThreadIdentifier = 0xffffffff;
78d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
79d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wunamespace blink {
80d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
81382eb1a728b30fd6a9c09842e233c9bd1f96f19bBrian Paul// Don't allow more than this number of simultaneous AudioContexts talking to hardware.
82d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuconst unsigned MaxHardwareContexts = 6;
83d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuunsigned AudioContext::s_hardwareContextCount = 0;
84d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
85d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuAudioContext* AudioContext::create(Document& document, ExceptionState& exceptionState)
86d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
87d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
88d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (s_hardwareContextCount >= MaxHardwareContexts) {
89d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
90d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            SyntaxError,
91d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "number of hardware contexts reached maximum (" + String::number(MaxHardwareContexts) + ").");
92d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
93d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
94d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
95d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    AudioContext* audioContext = adoptRefCountedGarbageCollectedWillBeNoop(new AudioContext(&document));
96d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    audioContext->suspendIfNeeded();
97d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return audioContext;
98d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
99d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
100d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu// Constructor for rendering to the audio hardware.
101d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuAudioContext::AudioContext(Document* document)
102d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    : ActiveDOMObject(document)
103d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_isStopScheduled(false)
104d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_isCleared(false)
105d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_isInitialized(false)
106d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_destinationNode(nullptr)
107d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_automaticPullNodesNeedUpdating(false)
108d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_connectionCount(0)
109d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_audioThread(0)
110d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_graphOwnerThread(UndefinedThreadIdentifier)
111d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_isOfflineContext(false)
112d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
113d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_destinationNode = DefaultAudioDestinationNode::create(this);
114d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
115d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    initialize();
116d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#if DEBUG_AUDIONODE_REFERENCES
117d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    fprintf(stderr, "%p: AudioContext::AudioContext() #%u\n", this, AudioContext::s_hardwareContextCount);
118d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#endif
119d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
120d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
121d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu// Constructor for offline (non-realtime) rendering.
122382eb1a728b30fd6a9c09842e233c9bd1f96f19bBrian PaulAudioContext::AudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
123d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    : ActiveDOMObject(document)
124d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_isStopScheduled(false)
125d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    , m_isCleared(false)
1265f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz    , m_isInitialized(false)
1275f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz    , m_destinationNode(nullptr)
1285f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz    , m_automaticPullNodesNeedUpdating(false)
129a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    , m_connectionCount(0)
130a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    , m_audioThread(0)
131a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    , m_graphOwnerThread(UndefinedThreadIdentifier)
132a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    , m_isOfflineContext(true)
133a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz{
134a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    // Create a new destination for offline rendering.
135a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    m_renderTarget = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
136a93f9f343a64ce91587af66761399f9d4c180015Jakob Bornecrantz    if (m_renderTarget.get())
1375f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz        m_destinationNode = OfflineAudioDestinationNode::create(this, m_renderTarget.get());
1385f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz
1395f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz    initialize();
140d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
141d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
142d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuAudioContext::~AudioContext()
143d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
144d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#if DEBUG_AUDIONODE_REFERENCES
145287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell    fprintf(stderr, "%p: AudioContext::~AudioContext()\n", this);
146d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu#endif
147d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
148d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(!m_isInitialized);
149d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(!m_referencedNodes.size());
150d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(!m_finishedNodes.size());
151d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(!m_automaticPullNodes.size());
152d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (m_automaticPullNodesNeedUpdating)
153d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
154d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(!m_renderingAutomaticPullNodes.size());
155d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
156d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
157d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuvoid AudioContext::initialize()
158287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell{
159d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (isInitialized())
160d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return;
161d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
162d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    FFTFrame::initialize();
163d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_listener = AudioListener::create();
164d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
165d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (m_destinationNode.get()) {
166d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        m_destinationNode->initialize();
167287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell
168d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        if (!isOfflineContext()) {
169d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
170d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a "render quantum".
171d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            // NOTE: for now default AudioContext does not need an explicit startRendering() call from JavaScript.
172d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            // We may want to consider requiring it for symmetry with OfflineAudioContext.
173d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            m_destinationNode->startRendering();
174d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            ++s_hardwareContextCount;
175d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        }
176d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
177d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        m_isInitialized = true;
178d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
179d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
180d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
181d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuvoid AudioContext::clear()
182d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
183d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // We need to run disposers before destructing m_contextGraphMutex.
184d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_liveAudioSummingJunctions.clear();
185d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_liveNodes.clear();
186d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_destinationNode.clear();
187d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_isCleared = true;
188d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
189d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
190d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuvoid AudioContext::uninitialize()
191d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
192d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
193d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
194d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (!isInitialized())
195d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return;
196d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
197d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // This stops the audio thread and all audio rendering.
198d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_destinationNode->uninitialize();
199d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
2004531356817ec8383ac35932903773de67af92e37Chia-I Wu    if (!isOfflineContext()) {
2014531356817ec8383ac35932903773de67af92e37Chia-I Wu        ASSERT(s_hardwareContextCount);
2024531356817ec8383ac35932903773de67af92e37Chia-I Wu        --s_hardwareContextCount;
2034531356817ec8383ac35932903773de67af92e37Chia-I Wu    }
2044531356817ec8383ac35932903773de67af92e37Chia-I Wu
2054531356817ec8383ac35932903773de67af92e37Chia-I Wu    // Get rid of the sources which may still be playing.
2064531356817ec8383ac35932903773de67af92e37Chia-I Wu    derefUnfinishedSourceNodes();
2074531356817ec8383ac35932903773de67af92e37Chia-I Wu
2084531356817ec8383ac35932903773de67af92e37Chia-I Wu    m_isInitialized = false;
2094531356817ec8383ac35932903773de67af92e37Chia-I Wu    ASSERT(m_listener);
2104531356817ec8383ac35932903773de67af92e37Chia-I Wu    m_listener->waitForHRTFDatabaseLoaderThreadCompletion();
2114531356817ec8383ac35932903773de67af92e37Chia-I Wu
2124531356817ec8383ac35932903773de67af92e37Chia-I Wu    clear();
2134531356817ec8383ac35932903773de67af92e37Chia-I Wu}
2144531356817ec8383ac35932903773de67af92e37Chia-I Wu
2154531356817ec8383ac35932903773de67af92e37Chia-I Wuvoid AudioContext::stop()
2164531356817ec8383ac35932903773de67af92e37Chia-I Wu{
2174531356817ec8383ac35932903773de67af92e37Chia-I Wu    // Usually ExecutionContext calls stop twice.
2184531356817ec8383ac35932903773de67af92e37Chia-I Wu    if (m_isStopScheduled)
2194531356817ec8383ac35932903773de67af92e37Chia-I Wu        return;
2204531356817ec8383ac35932903773de67af92e37Chia-I Wu    m_isStopScheduled = true;
2214531356817ec8383ac35932903773de67af92e37Chia-I Wu
2224531356817ec8383ac35932903773de67af92e37Chia-I Wu    // Don't call uninitialize() immediately here because the ExecutionContext is in the middle
2234531356817ec8383ac35932903773de67af92e37Chia-I Wu    // of dealing with all of its ActiveDOMObjects at this point. uninitialize() can de-reference other
2244531356817ec8383ac35932903773de67af92e37Chia-I Wu    // ActiveDOMObjects so let's schedule uninitialize() to be called later.
2254531356817ec8383ac35932903773de67af92e37Chia-I Wu    // FIXME: see if there's a more direct way to handle this issue.
2264531356817ec8383ac35932903773de67af92e37Chia-I Wu    callOnMainThread(bind(&AudioContext::uninitialize, this));
2274531356817ec8383ac35932903773de67af92e37Chia-I Wu}
2284531356817ec8383ac35932903773de67af92e37Chia-I Wu
2294531356817ec8383ac35932903773de67af92e37Chia-I Wubool AudioContext::hasPendingActivity() const
2304531356817ec8383ac35932903773de67af92e37Chia-I Wu{
231d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // According to spec AudioContext must die only after page navigates.
232d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return !m_isCleared;
233d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
234d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
235d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuAudioBuffer* AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
236d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
237d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate, exceptionState);
238d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
239d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
240d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wuvoid AudioContext::decodeAudioData(ArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionState& exceptionState)
241d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
242d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (!audioData) {
243d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
244d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            SyntaxError,
245d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "invalid ArrayBuffer for audioData.");
246d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return;
247d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
248d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    m_audioDecoder.decodeAsync(audioData, sampleRate(), successCallback, errorCallback);
249d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
250d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
251d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuAudioBufferSourceNode* AudioContext::createBufferSource()
252d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
253d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
254d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    AudioBufferSourceNode* node = AudioBufferSourceNode::create(this, m_destinationNode->sampleRate());
255d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
256d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
257d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
258d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    refNode(node);
259d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
260d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return node;
261d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
262d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
263d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuMediaElementAudioSourceNode* AudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState)
264d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
265d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
266d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (!mediaElement) {
267d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
268d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            InvalidStateError,
269d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "invalid HTMLMedialElement.");
270d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
271d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
272d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
273d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // First check if this media element already has a source node.
274d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (mediaElement->audioSourceNode()) {
275d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
276d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            InvalidStateError,
277d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "invalid HTMLMediaElement.");
278d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
279d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
280d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
281d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    MediaElementAudioSourceNode* node = MediaElementAudioSourceNode::create(this, mediaElement);
282d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
283d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    mediaElement->setAudioSourceNode(node);
284d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
285d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    refNode(node); // context keeps reference until node is disconnected
286d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return node;
287d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
288d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
289d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuMediaStreamAudioSourceNode* AudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState)
290d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
291d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
292287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell    if (!mediaStream) {
293d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
294d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            InvalidStateError,
295d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "invalid MediaStream source");
296d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
297d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
298d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
299d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    MediaStreamTrackVector audioTracks = mediaStream->getAudioTracks();
300d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (audioTracks.isEmpty()) {
301d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
302d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            InvalidStateError,
303d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "MediaStream has no audio track");
304d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
305d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
306d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
307d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // Use the first audio track in the media stream.
308d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    MediaStreamTrack* audioTrack = audioTracks[0];
309d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    OwnPtr<AudioSourceProvider> provider = audioTrack->createWebAudioSource();
310d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    MediaStreamAudioSourceNode* node = MediaStreamAudioSourceNode::create(this, mediaStream, audioTrack, provider.release());
311d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
312d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // FIXME: Only stereo streams are supported right now. We should be able to accept multi-channel streams.
313d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    node->setFormat(2, sampleRate());
314d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
315d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    refNode(node); // context keeps reference until node is disconnected
316d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return node;
317d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
318d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
319d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuMediaStreamAudioDestinationNode* AudioContext::createMediaStreamDestination()
320d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
321d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // Set number of output channels to stereo by default.
322d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return MediaStreamAudioDestinationNode::create(this, 2);
323d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
324d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
325d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuScriptProcessorNode* AudioContext::createScriptProcessor(ExceptionState& exceptionState)
326d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
327d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // Set number of input/output channels to stereo by default.
328d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return createScriptProcessor(0, 2, 2, exceptionState);
329d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
330d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
331d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, ExceptionState& exceptionState)
332d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
333d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // Set number of input/output channels to stereo by default.
334d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return createScriptProcessor(bufferSize, 2, 2, exceptionState);
335d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
336d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
337d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState& exceptionState)
338d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
339d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    // Set number of output channels to stereo by default.
340d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return createScriptProcessor(bufferSize, numberOfInputChannels, 2, exceptionState);
341d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
342d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
343d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuScriptProcessorNode* AudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState)
344d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
345287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell    ASSERT(isMainThread());
346d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ScriptProcessorNode* node = ScriptProcessorNode::create(this, m_destinationNode->sampleRate(), bufferSize, numberOfInputChannels, numberOfOutputChannels);
347d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
348d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (!node) {
349d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        if (!numberOfInputChannels && !numberOfOutputChannels) {
350d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            exceptionState.throwDOMException(
351d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                IndexSizeError,
352d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                "number of input channels and output channels cannot both be zero.");
353d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        } else if (numberOfInputChannels > AudioContext::maxNumberOfChannels()) {
354d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            exceptionState.throwDOMException(
355d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                IndexSizeError,
356d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                "number of input channels (" + String::number(numberOfInputChannels)
357d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                + ") exceeds maximum ("
358d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                + String::number(AudioContext::maxNumberOfChannels()) + ").");
359d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        } else if (numberOfOutputChannels > AudioContext::maxNumberOfChannels()) {
360d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            exceptionState.throwDOMException(
361d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                IndexSizeError,
362d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                "number of output channels (" + String::number(numberOfInputChannels)
363d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                + ") exceeds maximum ("
364d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                + String::number(AudioContext::maxNumberOfChannels()) + ").");
365d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        } else {
366d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            exceptionState.throwDOMException(
367d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                IndexSizeError,
368d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                "buffer size (" + String::number(bufferSize)
369d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu                + ") must be a power of two between 256 and 16384.");
370d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        }
371d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
372d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
373d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
374d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    refNode(node); // context keeps reference until we stop making javascript rendering callbacks
375d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return node;
3764db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz}
3774db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz
3784db0c760195c67f1bc114fdfb8464791030a526cJakob BorncrantzBiquadFilterNode* AudioContext::createBiquadFilter()
3794db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz{
3804db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz    ASSERT(isMainThread());
3814db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz    return BiquadFilterNode::create(this, m_destinationNode->sampleRate());
3824db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz}
3834db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz
3844db0c760195c67f1bc114fdfb8464791030a526cJakob BorncrantzWaveShaperNode* AudioContext::createWaveShaper()
3854db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz{
386d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
387d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return WaveShaperNode::create(this);
388d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
3894db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz
3904db0c760195c67f1bc114fdfb8464791030a526cJakob BorncrantzPannerNode* AudioContext::createPanner()
3914db0c760195c67f1bc114fdfb8464791030a526cJakob Borncrantz{
3925f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz    ASSERT(isMainThread());
3935f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz    return PannerNode::create(this, m_destinationNode->sampleRate());
3945f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz}
3955f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz
3965f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob BornecrantzConvolverNode* AudioContext::createConvolver()
3975f66363f8ed26d6f3fc8fcccde804fe1fea1bbaaJakob Bornecrantz{
398d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
399d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return ConvolverNode::create(this, m_destinationNode->sampleRate());
400d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
401d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
402d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuDynamicsCompressorNode* AudioContext::createDynamicsCompressor()
403d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
404d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
405d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return DynamicsCompressorNode::create(this, m_destinationNode->sampleRate());
406d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
407d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
4084531356817ec8383ac35932903773de67af92e37Chia-I WuAnalyserNode* AudioContext::createAnalyser()
4094531356817ec8383ac35932903773de67af92e37Chia-I Wu{
4104531356817ec8383ac35932903773de67af92e37Chia-I Wu    ASSERT(isMainThread());
4114531356817ec8383ac35932903773de67af92e37Chia-I Wu    return AnalyserNode::create(this, m_destinationNode->sampleRate());
4124531356817ec8383ac35932903773de67af92e37Chia-I Wu}
4134531356817ec8383ac35932903773de67af92e37Chia-I Wu
4144531356817ec8383ac35932903773de67af92e37Chia-I WuGainNode* AudioContext::createGain()
4154531356817ec8383ac35932903773de67af92e37Chia-I Wu{
4164531356817ec8383ac35932903773de67af92e37Chia-I Wu    ASSERT(isMainThread());
4174531356817ec8383ac35932903773de67af92e37Chia-I Wu    return GainNode::create(this, m_destinationNode->sampleRate());
418d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
419d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
420d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuDelayNode* AudioContext::createDelay(ExceptionState& exceptionState)
421d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
422d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    const double defaultMaxDelayTime = 1;
423d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return createDelay(defaultMaxDelayTime, exceptionState);
424d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
425d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
426d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuDelayNode* AudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState)
427d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
428d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
429d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    DelayNode* node = DelayNode::create(this, m_destinationNode->sampleRate(), maxDelayTime, exceptionState);
430d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (exceptionState.hadException())
431d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
432d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return node;
433d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
4344531356817ec8383ac35932903773de67af92e37Chia-I Wu
435d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuChannelSplitterNode* AudioContext::createChannelSplitter(ExceptionState& exceptionState)
436d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
437d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    const unsigned ChannelSplitterDefaultNumberOfOutputs = 6;
438d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return createChannelSplitter(ChannelSplitterDefaultNumberOfOutputs, exceptionState);
439d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
4404531356817ec8383ac35932903773de67af92e37Chia-I Wu
4414531356817ec8383ac35932903773de67af92e37Chia-I WuChannelSplitterNode* AudioContext::createChannelSplitter(size_t numberOfOutputs, ExceptionState& exceptionState)
442d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
443d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ASSERT(isMainThread());
444d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
445d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    ChannelSplitterNode* node = ChannelSplitterNode::create(this, m_destinationNode->sampleRate(), numberOfOutputs);
446d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
447d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    if (!node) {
448d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        exceptionState.throwDOMException(
449d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            IndexSizeError,
450d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            "number of outputs (" + String::number(numberOfOutputs)
451d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            + ") must be between 1 and "
452d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            + String::number(AudioContext::maxNumberOfChannels()) + ".");
453d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
454d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    }
455d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
456d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return node;
457d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
458d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu
459d2083056d56990a9bfba774d5bda272b74d27a6fChia-I WuChannelMergerNode* AudioContext::createChannelMerger(ExceptionState& exceptionState)
460d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu{
461d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    const unsigned ChannelMergerDefaultNumberOfInputs = 6;
462d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu    return createChannelMerger(ChannelMergerDefaultNumberOfInputs, exceptionState);
463d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu}
4640c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz
4650c572c6828b6a338b07a6860280b3a314a81662eJakob BornecrantzChannelMergerNode* AudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState)
4660c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz{
4670c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz    ASSERT(isMainThread());
4680c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz
4690c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz    ChannelMergerNode* node = ChannelMergerNode::create(this, m_destinationNode->sampleRate(), numberOfInputs);
4700c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz
4710c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz    if (!node) {
4720c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz        exceptionState.throwDOMException(
4730c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz            IndexSizeError,
4740c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz            "number of inputs (" + String::number(numberOfInputs)
4750c572c6828b6a338b07a6860280b3a314a81662eJakob Bornecrantz            + ") must be between 1 and "
476d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu            + String::number(AudioContext::maxNumberOfChannels()) + ".");
477d2083056d56990a9bfba774d5bda272b74d27a6fChia-I Wu        return 0;
478    }
479
480    return node;
481}
482
483OscillatorNode* AudioContext::createOscillator()
484{
485    ASSERT(isMainThread());
486
487    OscillatorNode* node = OscillatorNode::create(this, m_destinationNode->sampleRate());
488
489    // Because this is an AudioScheduledSourceNode, the context keeps a reference until it has finished playing.
490    // When this happens, AudioScheduledSourceNode::finish() calls AudioContext::notifyNodeFinishedProcessing().
491    refNode(node);
492
493    return node;
494}
495
496PeriodicWave* AudioContext::createPeriodicWave(Float32Array* real, Float32Array* imag, ExceptionState& exceptionState)
497{
498    ASSERT(isMainThread());
499
500    if (!real) {
501        exceptionState.throwDOMException(
502            SyntaxError,
503            "invalid real array");
504        return 0;
505    }
506
507    if (!imag) {
508        exceptionState.throwDOMException(
509            SyntaxError,
510            "invalid imaginary array");
511        return 0;
512    }
513
514    if (real->length() != imag->length()) {
515        exceptionState.throwDOMException(
516            IndexSizeError,
517            "length of real array (" + String::number(real->length())
518            + ") and length of imaginary array (" +  String::number(imag->length())
519            + ") must match.");
520        return 0;
521    }
522
523    if (real->length() > 4096) {
524        exceptionState.throwDOMException(
525            IndexSizeError,
526            "length of real array (" + String::number(real->length())
527            + ") exceeds allowed maximum of 4096");
528        return 0;
529    }
530
531    if (imag->length() > 4096) {
532        exceptionState.throwDOMException(
533            IndexSizeError,
534            "length of imaginary array (" + String::number(imag->length())
535            + ") exceeds allowed maximum of 4096");
536        return 0;
537    }
538
539    return PeriodicWave::create(sampleRate(), real, imag);
540}
541
542void AudioContext::notifyNodeFinishedProcessing(AudioNode* node)
543{
544    ASSERT(isAudioThread());
545    m_finishedNodes.append(node);
546}
547
548void AudioContext::derefFinishedSourceNodes()
549{
550    ASSERT(isGraphOwner());
551    ASSERT(isAudioThread());
552    for (unsigned i = 0; i < m_finishedNodes.size(); i++)
553        derefNode(m_finishedNodes[i]);
554
555    m_finishedNodes.clear();
556}
557
558void AudioContext::refNode(AudioNode* node)
559{
560    ASSERT(isMainThread());
561    AutoLocker locker(this);
562
563    m_referencedNodes.append(node);
564    node->makeConnection();
565}
566
567void AudioContext::derefNode(AudioNode* node)
568{
569    ASSERT(isGraphOwner());
570
571    for (unsigned i = 0; i < m_referencedNodes.size(); ++i) {
572        if (node == m_referencedNodes[i].get()) {
573            node->breakConnection();
574            m_referencedNodes.remove(i);
575            break;
576        }
577    }
578}
579
580void AudioContext::derefUnfinishedSourceNodes()
581{
582    ASSERT(isMainThread());
583    for (unsigned i = 0; i < m_referencedNodes.size(); ++i)
584        m_referencedNodes[i]->breakConnection();
585
586    m_referencedNodes.clear();
587}
588
589void AudioContext::lock(bool& mustReleaseLock)
590{
591    // Don't allow regular lock in real-time audio thread.
592    ASSERT(isMainThread());
593
594    ThreadIdentifier thisThread = currentThread();
595
596    if (thisThread == m_graphOwnerThread) {
597        // We already have the lock.
598        mustReleaseLock = false;
599    } else {
600        // Acquire the lock.
601        m_contextGraphMutex.lock();
602        m_graphOwnerThread = thisThread;
603        mustReleaseLock = true;
604    }
605}
606
607bool AudioContext::tryLock(bool& mustReleaseLock)
608{
609    ThreadIdentifier thisThread = currentThread();
610    bool isAudioThread = thisThread == audioThread();
611
612    // Try to catch cases of using try lock on main thread - it should use regular lock.
613    ASSERT(isAudioThread);
614
615    if (!isAudioThread) {
616        // In release build treat tryLock() as lock() (since above ASSERT(isAudioThread) never fires) - this is the best we can do.
617        lock(mustReleaseLock);
618        return true;
619    }
620
621    bool hasLock;
622
623    if (thisThread == m_graphOwnerThread) {
624        // Thread already has the lock.
625        hasLock = true;
626        mustReleaseLock = false;
627    } else {
628        // Don't already have the lock - try to acquire it.
629        hasLock = m_contextGraphMutex.tryLock();
630
631        if (hasLock)
632            m_graphOwnerThread = thisThread;
633
634        mustReleaseLock = hasLock;
635    }
636
637    return hasLock;
638}
639
640void AudioContext::unlock()
641{
642    ASSERT(currentThread() == m_graphOwnerThread);
643
644    m_graphOwnerThread = UndefinedThreadIdentifier;
645    m_contextGraphMutex.unlock();
646}
647
648bool AudioContext::isAudioThread() const
649{
650    return currentThread() == m_audioThread;
651}
652
653bool AudioContext::isGraphOwner() const
654{
655    return currentThread() == m_graphOwnerThread;
656}
657
658void AudioContext::addDeferredBreakConnection(AudioNode& node)
659{
660    ASSERT(isAudioThread());
661    m_deferredBreakConnectionList.append(&node);
662}
663
664void AudioContext::handlePreRenderTasks()
665{
666    ASSERT(isAudioThread());
667
668    // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
669    // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
670    bool mustReleaseLock;
671    if (tryLock(mustReleaseLock)) {
672        // Update the channel count mode.
673        updateChangedChannelCountMode();
674
675        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
676        handleDirtyAudioSummingJunctions();
677        handleDirtyAudioNodeOutputs();
678
679        updateAutomaticPullNodes();
680
681        if (mustReleaseLock)
682            unlock();
683    }
684}
685
686void AudioContext::handlePostRenderTasks()
687{
688    ASSERT(isAudioThread());
689
690    // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
691    // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
692    // from the render graph (in which case they'll render silence).
693    bool mustReleaseLock;
694    if (tryLock(mustReleaseLock)) {
695        // Update the channel count mode.
696        updateChangedChannelCountMode();
697
698        // Take care of AudioNode tasks where the tryLock() failed previously.
699        handleDeferredAudioNodeTasks();
700
701        // Dynamically clean up nodes which are no longer needed.
702        derefFinishedSourceNodes();
703
704        // Fixup the state of any dirty AudioSummingJunctions and AudioNodeOutputs.
705        handleDirtyAudioSummingJunctions();
706        handleDirtyAudioNodeOutputs();
707
708        updateAutomaticPullNodes();
709
710        if (mustReleaseLock)
711            unlock();
712    }
713}
714
715void AudioContext::handleDeferredAudioNodeTasks()
716{
717    ASSERT(isAudioThread() && isGraphOwner());
718
719    for (unsigned i = 0; i < m_deferredBreakConnectionList.size(); ++i)
720        m_deferredBreakConnectionList[i]->breakConnectionWithLock();
721    m_deferredBreakConnectionList.clear();
722}
723
724void AudioContext::registerLiveNode(AudioNode& node)
725{
726    ASSERT(isMainThread());
727    m_liveNodes.add(&node, adoptPtr(new AudioNodeDisposer(node)));
728}
729
730AudioContext::AudioNodeDisposer::~AudioNodeDisposer()
731{
732    ASSERT(isMainThread());
733    AudioContext::AutoLocker locker(m_node.context());
734    m_node.dispose();
735}
736
737void AudioContext::registerLiveAudioSummingJunction(AudioSummingJunction& junction)
738{
739    ASSERT(isMainThread());
740    m_liveAudioSummingJunctions.add(&junction, adoptPtr(new AudioSummingJunctionDisposer(junction)));
741}
742
743AudioContext::AudioSummingJunctionDisposer::~AudioSummingJunctionDisposer()
744{
745    ASSERT(isMainThread());
746    m_junction.dispose();
747}
748
749void AudioContext::disposeOutputs(AudioNode& node)
750{
751    ASSERT(isGraphOwner());
752    ASSERT(isMainThread());
753    for (unsigned i = 0; i < node.numberOfOutputs(); ++i)
754        node.output(i)->dispose();
755}
756
757void AudioContext::markSummingJunctionDirty(AudioSummingJunction* summingJunction)
758{
759    ASSERT(isGraphOwner());
760    m_dirtySummingJunctions.add(summingJunction);
761}
762
763void AudioContext::removeMarkedSummingJunction(AudioSummingJunction* summingJunction)
764{
765    ASSERT(isMainThread());
766    AutoLocker locker(this);
767    m_dirtySummingJunctions.remove(summingJunction);
768}
769
770void AudioContext::markAudioNodeOutputDirty(AudioNodeOutput* output)
771{
772    ASSERT(isGraphOwner());
773    ASSERT(isMainThread());
774    m_dirtyAudioNodeOutputs.add(output);
775}
776
777void AudioContext::removeMarkedAudioNodeOutput(AudioNodeOutput* output)
778{
779    ASSERT(isGraphOwner());
780    ASSERT(isMainThread());
781    m_dirtyAudioNodeOutputs.remove(output);
782}
783
784void AudioContext::handleDirtyAudioSummingJunctions()
785{
786    ASSERT(isGraphOwner());
787
788    for (HashSet<AudioSummingJunction*>::iterator i = m_dirtySummingJunctions.begin(); i != m_dirtySummingJunctions.end(); ++i)
789        (*i)->updateRenderingState();
790
791    m_dirtySummingJunctions.clear();
792}
793
794void AudioContext::handleDirtyAudioNodeOutputs()
795{
796    ASSERT(isGraphOwner());
797
798    for (HashSet<AudioNodeOutput*>::iterator i = m_dirtyAudioNodeOutputs.begin(); i != m_dirtyAudioNodeOutputs.end(); ++i)
799        (*i)->updateRenderingState();
800
801    m_dirtyAudioNodeOutputs.clear();
802}
803
804void AudioContext::addAutomaticPullNode(AudioNode* node)
805{
806    ASSERT(isGraphOwner());
807
808    if (!m_automaticPullNodes.contains(node)) {
809        m_automaticPullNodes.add(node);
810        m_automaticPullNodesNeedUpdating = true;
811    }
812}
813
814void AudioContext::removeAutomaticPullNode(AudioNode* node)
815{
816    ASSERT(isGraphOwner());
817
818    if (m_automaticPullNodes.contains(node)) {
819        m_automaticPullNodes.remove(node);
820        m_automaticPullNodesNeedUpdating = true;
821    }
822}
823
824void AudioContext::updateAutomaticPullNodes()
825{
826    ASSERT(isGraphOwner());
827
828    if (m_automaticPullNodesNeedUpdating) {
829        // Copy from m_automaticPullNodes to m_renderingAutomaticPullNodes.
830        m_renderingAutomaticPullNodes.resize(m_automaticPullNodes.size());
831
832        unsigned j = 0;
833        for (HashSet<AudioNode*>::iterator i = m_automaticPullNodes.begin(); i != m_automaticPullNodes.end(); ++i, ++j) {
834            AudioNode* output = *i;
835            m_renderingAutomaticPullNodes[j] = output;
836        }
837
838        m_automaticPullNodesNeedUpdating = false;
839    }
840}
841
842void AudioContext::processAutomaticPullNodes(size_t framesToProcess)
843{
844    ASSERT(isAudioThread());
845
846    for (unsigned i = 0; i < m_renderingAutomaticPullNodes.size(); ++i)
847        m_renderingAutomaticPullNodes[i]->processIfNecessary(framesToProcess);
848}
849
850const AtomicString& AudioContext::interfaceName() const
851{
852    return EventTargetNames::AudioContext;
853}
854
855ExecutionContext* AudioContext::executionContext() const
856{
857    return m_isStopScheduled ? 0 : ActiveDOMObject::executionContext();
858}
859
860void AudioContext::startRendering()
861{
862    destination()->startRendering();
863}
864
865void AudioContext::fireCompletionEvent()
866{
867    ASSERT(isMainThread());
868    if (!isMainThread())
869        return;
870
871    AudioBuffer* renderedBuffer = m_renderTarget.get();
872
873    ASSERT(renderedBuffer);
874    if (!renderedBuffer)
875        return;
876
877    // Avoid firing the event if the document has already gone away.
878    if (executionContext()) {
879        // Call the offline rendering completion event listener.
880        dispatchEvent(OfflineAudioCompletionEvent::create(renderedBuffer));
881    }
882}
883
884void AudioContext::trace(Visitor* visitor)
885{
886    visitor->trace(m_renderTarget);
887    visitor->trace(m_destinationNode);
888    visitor->trace(m_listener);
889    visitor->trace(m_referencedNodes);
890    visitor->trace(m_liveNodes);
891    visitor->trace(m_liveAudioSummingJunctions);
892    EventTargetWithInlineData::trace(visitor);
893}
894
895void AudioContext::addChangedChannelCountMode(AudioNode* node)
896{
897    ASSERT(isGraphOwner());
898    ASSERT(isMainThread());
899    m_deferredCountModeChange.add(node);
900}
901
902void AudioContext::removeChangedChannelCountMode(AudioNode* node)
903{
904    ASSERT(isGraphOwner());
905
906    m_deferredCountModeChange.remove(node);
907}
908
909void AudioContext::updateChangedChannelCountMode()
910{
911    ASSERT(isGraphOwner());
912
913    for (HashSet<AudioNode*>::iterator k = m_deferredCountModeChange.begin(); k != m_deferredCountModeChange.end(); ++k)
914        (*k)->updateChannelCountMode();
915
916    m_deferredCountModeChange.clear();
917}
918
919} // namespace blink
920
921#endif // ENABLE(WEB_AUDIO)
922