2 * Copyright (C) 2010, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "modules/webaudio/ScriptProcessorNode.h"
31 #include "core/dom/CrossThreadTask.h"
32 #include "core/dom/ExecutionContext.h"
33 #include "modules/webaudio/AudioBuffer.h"
34 #include "modules/webaudio/AudioContext.h"
35 #include "modules/webaudio/AudioNodeInput.h"
36 #include "modules/webaudio/AudioNodeOutput.h"
37 #include "modules/webaudio/AudioProcessingEvent.h"
38 #include "public/platform/Platform.h"
39 #include "wtf/Float32Array.h"
43 static size_t chooseBufferSize()
45 // Choose a buffer size based on the audio hardware buffer size. Arbitarily make it a power of
46 // two that is 4 times greater than the hardware buffer size.
47 // FIXME: What is the best way to choose this?
48 size_t hardwareBufferSize = Platform::current()->audioHardwareBufferSize();
49 size_t bufferSize = 1 << static_cast<unsigned>(log2(4 * hardwareBufferSize) + 0.5);
53 if (bufferSize > 16384)
59 ScriptProcessorNode* ScriptProcessorNode::create(AudioContext* context, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
61 // Check for valid buffer size.
64 bufferSize = chooseBufferSize();
78 if (!numberOfInputChannels && !numberOfOutputChannels)
81 if (numberOfInputChannels > AudioContext::maxNumberOfChannels())
84 if (numberOfOutputChannels > AudioContext::maxNumberOfChannels())
87 return adoptRefCountedGarbageCollectedWillBeNoop(new ScriptProcessorNode(context, sampleRate, bufferSize, numberOfInputChannels, numberOfOutputChannels));
90 ScriptProcessorNode::ScriptProcessorNode(AudioContext* context, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
91 : AudioNode(context, sampleRate)
92 , m_doubleBufferIndex(0)
93 , m_doubleBufferIndexForEvent(0)
94 , m_bufferSize(bufferSize)
95 , m_bufferReadWriteIndex(0)
96 , m_numberOfInputChannels(numberOfInputChannels)
97 , m_numberOfOutputChannels(numberOfOutputChannels)
98 , m_internalInputBus(AudioBus::create(numberOfInputChannels, AudioNode::ProcessingSizeInFrames, false))
100 // Regardless of the allowed buffer sizes, we still need to process at the granularity of the AudioNode.
101 if (m_bufferSize < AudioNode::ProcessingSizeInFrames)
102 m_bufferSize = AudioNode::ProcessingSizeInFrames;
104 ASSERT(numberOfInputChannels <= AudioContext::maxNumberOfChannels());
107 addOutput(AudioNodeOutput::create(this, numberOfOutputChannels));
109 setNodeType(NodeTypeJavaScript);
114 ScriptProcessorNode::~ScriptProcessorNode()
116 ASSERT(!isInitialized());
119 void ScriptProcessorNode::dispose()
122 AudioNode::dispose();
125 void ScriptProcessorNode::initialize()
130 float sampleRate = context()->sampleRate();
132 // Create double buffers on both the input and output sides.
133 // These AudioBuffers will be directly accessed in the main thread by JavaScript.
134 for (unsigned i = 0; i < 2; ++i) {
135 AudioBuffer* inputBuffer = m_numberOfInputChannels ? AudioBuffer::create(m_numberOfInputChannels, bufferSize(), sampleRate) : 0;
136 AudioBuffer* outputBuffer = m_numberOfOutputChannels ? AudioBuffer::create(m_numberOfOutputChannels, bufferSize(), sampleRate) : 0;
138 m_inputBuffers.append(inputBuffer);
139 m_outputBuffers.append(outputBuffer);
142 AudioNode::initialize();
145 void ScriptProcessorNode::uninitialize()
147 if (!isInitialized())
150 m_inputBuffers.clear();
151 m_outputBuffers.clear();
153 AudioNode::uninitialize();
156 void ScriptProcessorNode::process(size_t framesToProcess)
158 // Discussion about inputs and outputs:
159 // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input and output (see inputBus and outputBus below).
160 // Additionally, there is a double-buffering for input and output which is exposed directly to JavaScript (see inputBuffer and outputBuffer below).
161 // This node is the producer for inputBuffer and the consumer for outputBuffer.
162 // The JavaScript code is the consumer of inputBuffer and the producer for outputBuffer.
164 // Get input and output busses.
165 AudioBus* inputBus = this->input(0)->bus();
166 AudioBus* outputBus = this->output(0)->bus();
168 // Get input and output buffers. We double-buffer both the input and output sides.
169 unsigned doubleBufferIndex = this->doubleBufferIndex();
170 bool isDoubleBufferIndexGood = doubleBufferIndex < 2 && doubleBufferIndex < m_inputBuffers.size() && doubleBufferIndex < m_outputBuffers.size();
171 ASSERT(isDoubleBufferIndexGood);
172 if (!isDoubleBufferIndexGood)
175 AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get();
176 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get();
178 // Check the consistency of input and output buffers.
179 unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels();
180 bool buffersAreGood = outputBuffer && bufferSize() == outputBuffer->length() && m_bufferReadWriteIndex + framesToProcess <= bufferSize();
182 // If the number of input channels is zero, it's ok to have inputBuffer = 0.
183 if (m_internalInputBus->numberOfChannels())
184 buffersAreGood = buffersAreGood && inputBuffer && bufferSize() == inputBuffer->length();
186 ASSERT(buffersAreGood);
190 // We assume that bufferSize() is evenly divisible by framesToProcess - should always be true, but we should still check.
191 bool isFramesToProcessGood = framesToProcess && bufferSize() >= framesToProcess && !(bufferSize() % framesToProcess);
192 ASSERT(isFramesToProcessGood);
193 if (!isFramesToProcessGood)
196 unsigned numberOfOutputChannels = outputBus->numberOfChannels();
198 bool channelsAreGood = (numberOfInputChannels == m_numberOfInputChannels) && (numberOfOutputChannels == m_numberOfOutputChannels);
199 ASSERT(channelsAreGood);
200 if (!channelsAreGood)
203 for (unsigned i = 0; i < numberOfInputChannels; i++)
204 m_internalInputBus->setChannelMemory(i, inputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, framesToProcess);
206 if (numberOfInputChannels)
207 m_internalInputBus->copyFrom(*inputBus);
209 // Copy from the output buffer to the output.
210 for (unsigned i = 0; i < numberOfOutputChannels; ++i)
211 memcpy(outputBus->channel(i)->mutableData(), outputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, sizeof(float) * framesToProcess);
213 // Update the buffering index.
214 m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % bufferSize();
216 // m_bufferReadWriteIndex will wrap back around to 0 when the current input and output buffers are full.
217 // When this happens, fire an event and swap buffers.
218 if (!m_bufferReadWriteIndex) {
219 // Avoid building up requests on the main thread to fire process events when they're not being handled.
220 // This could be a problem if the main thread is very busy doing other things and is being held up handling previous requests.
221 // The audio thread can't block on this lock, so we call tryLock() instead.
222 MutexTryLocker tryLocker(m_processEventLock);
223 if (!tryLocker.locked()) {
224 // We're late in handling the previous request. The main thread must be very busy.
225 // The best we can do is clear out the buffer ourself here.
226 outputBuffer->zero();
227 } else if (context()->executionContext()) {
228 // Fire the event on the main thread, not this one (which is the realtime audio thread).
229 m_doubleBufferIndexForEvent = m_doubleBufferIndex;
230 context()->executionContext()->postTask(createCrossThreadTask(&ScriptProcessorNode::fireProcessEvent, this));
237 void ScriptProcessorNode::fireProcessEvent()
239 ASSERT(isMainThread());
241 bool isIndexGood = m_doubleBufferIndexForEvent < 2;
246 AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get();
247 AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get();
248 ASSERT(outputBuffer);
252 // Avoid firing the event if the document has already gone away.
253 if (context()->executionContext()) {
254 // This synchronizes with process().
255 MutexLocker processLocker(m_processEventLock);
257 // Calculate a playbackTime with the buffersize which needs to be processed each time onaudioprocess is called.
258 // The outputBuffer being passed to JS will be played after exhuasting previous outputBuffer by double-buffering.
259 double playbackTime = (context()->currentSampleFrame() + m_bufferSize) / static_cast<double>(context()->sampleRate());
261 // Call the JavaScript event handler which will do the audio processing.
262 dispatchEvent(AudioProcessingEvent::create(inputBuffer, outputBuffer, playbackTime));
266 double ScriptProcessorNode::tailTime() const
268 return std::numeric_limits<double>::infinity();
271 double ScriptProcessorNode::latencyTime() const
273 return std::numeric_limits<double>::infinity();
276 void ScriptProcessorNode::trace(Visitor* visitor)
278 visitor->trace(m_inputBuffers);
279 visitor->trace(m_outputBuffers);
280 AudioNode::trace(visitor);
285 #endif // ENABLE(WEB_AUDIO)