1/*
2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26
27#if ENABLE(WEB_AUDIO)
28
29#include "modules/webaudio/ScriptProcessorNode.h"
30
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"
40
41namespace blink {
42
43static size_t chooseBufferSize()
44{
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);
50
51    if (bufferSize < 256)
52        return 256;
53    if (bufferSize > 16384)
54        return 16384;
55
56    return bufferSize;
57}
58
59ScriptProcessorNode* ScriptProcessorNode::create(AudioContext* context, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
60{
61    // Check for valid buffer size.
62    switch (bufferSize) {
63    case 0:
64        bufferSize = chooseBufferSize();
65        break;
66    case 256:
67    case 512:
68    case 1024:
69    case 2048:
70    case 4096:
71    case 8192:
72    case 16384:
73        break;
74    default:
75        return 0;
76    }
77
78    if (!numberOfInputChannels && !numberOfOutputChannels)
79        return 0;
80
81    if (numberOfInputChannels > AudioContext::maxNumberOfChannels())
82        return 0;
83
84    if (numberOfOutputChannels > AudioContext::maxNumberOfChannels())
85        return 0;
86
87    return adoptRefCountedGarbageCollectedWillBeNoop(new ScriptProcessorNode(context, sampleRate, bufferSize, numberOfInputChannels, numberOfOutputChannels));
88}
89
90ScriptProcessorNode::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))
99{
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;
103
104    ASSERT(numberOfInputChannels <= AudioContext::maxNumberOfChannels());
105
106    addInput();
107    addOutput(AudioNodeOutput::create(this, numberOfOutputChannels));
108
109    setNodeType(NodeTypeJavaScript);
110
111    initialize();
112}
113
114ScriptProcessorNode::~ScriptProcessorNode()
115{
116    ASSERT(!isInitialized());
117}
118
119void ScriptProcessorNode::dispose()
120{
121    uninitialize();
122    AudioNode::dispose();
123}
124
125void ScriptProcessorNode::initialize()
126{
127    if (isInitialized())
128        return;
129
130    float sampleRate = context()->sampleRate();
131
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;
137
138        m_inputBuffers.append(inputBuffer);
139        m_outputBuffers.append(outputBuffer);
140    }
141
142    AudioNode::initialize();
143}
144
145void ScriptProcessorNode::uninitialize()
146{
147    if (!isInitialized())
148        return;
149
150    m_inputBuffers.clear();
151    m_outputBuffers.clear();
152
153    AudioNode::uninitialize();
154}
155
156void ScriptProcessorNode::process(size_t framesToProcess)
157{
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.
163
164    // Get input and output busses.
165    AudioBus* inputBus = this->input(0)->bus();
166    AudioBus* outputBus = this->output(0)->bus();
167
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)
173        return;
174
175    AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get();
176    AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get();
177
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();
181
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();
185
186    ASSERT(buffersAreGood);
187    if (!buffersAreGood)
188        return;
189
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)
194        return;
195
196    unsigned numberOfOutputChannels = outputBus->numberOfChannels();
197
198    bool channelsAreGood = (numberOfInputChannels == m_numberOfInputChannels) && (numberOfOutputChannels == m_numberOfOutputChannels);
199    ASSERT(channelsAreGood);
200    if (!channelsAreGood)
201        return;
202
203    for (unsigned i = 0; i < numberOfInputChannels; i++)
204        m_internalInputBus->setChannelMemory(i, inputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, framesToProcess);
205
206    if (numberOfInputChannels)
207        m_internalInputBus->copyFrom(*inputBus);
208
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);
212
213    // Update the buffering index.
214    m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % bufferSize();
215
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));
231        }
232
233        swapBuffers();
234    }
235}
236
237void ScriptProcessorNode::fireProcessEvent()
238{
239    ASSERT(isMainThread());
240
241    bool isIndexGood = m_doubleBufferIndexForEvent < 2;
242    ASSERT(isIndexGood);
243    if (!isIndexGood)
244        return;
245
246    AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get();
247    AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get();
248    ASSERT(outputBuffer);
249    if (!outputBuffer)
250        return;
251
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);
256
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());
260
261        // Call the JavaScript event handler which will do the audio processing.
262        dispatchEvent(AudioProcessingEvent::create(inputBuffer, outputBuffer, playbackTime));
263    }
264}
265
266double ScriptProcessorNode::tailTime() const
267{
268    return std::numeric_limits<double>::infinity();
269}
270
271double ScriptProcessorNode::latencyTime() const
272{
273    return std::numeric_limits<double>::infinity();
274}
275
276void ScriptProcessorNode::trace(Visitor* visitor)
277{
278    visitor->trace(m_inputBuffers);
279    visitor->trace(m_outputBuffers);
280    AudioNode::trace(visitor);
281}
282
283} // namespace blink
284
285#endif // ENABLE(WEB_AUDIO)
286