Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / webaudio / ScriptProcessorNode.cpp
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
41 namespace blink {
42
43 static 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
59 ScriptProcessorNode* 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
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))
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
114 ScriptProcessorNode::~ScriptProcessorNode()
115 {
116     ASSERT(!isInitialized());
117 }
118
119 void ScriptProcessorNode::dispose()
120 {
121     uninitialize();
122     AudioNode::dispose();
123 }
124
125 void 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
145 void ScriptProcessorNode::uninitialize()
146 {
147     if (!isInitialized())
148         return;
149
150     m_inputBuffers.clear();
151     m_outputBuffers.clear();
152
153     AudioNode::uninitialize();
154 }
155
156 void 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
237 void 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
266 double ScriptProcessorNode::tailTime() const
267 {
268     return std::numeric_limits<double>::infinity();
269 }
270
271 double ScriptProcessorNode::latencyTime() const
272 {
273     return std::numeric_limits<double>::infinity();
274 }
275
276 void 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)