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