OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 unsigned numberOfOutputChannels) | 45 unsigned numberOfOutputChannels) |
46 : AudioHandler(NodeTypeJavaScript, node, sampleRate), | 46 : AudioHandler(NodeTypeJavaScript, node, sampleRate), |
47 m_doubleBufferIndex(0), | 47 m_doubleBufferIndex(0), |
48 m_bufferSize(bufferSize), | 48 m_bufferSize(bufferSize), |
49 m_bufferReadWriteIndex(0), | 49 m_bufferReadWriteIndex(0), |
50 m_numberOfInputChannels(numberOfInputChannels), | 50 m_numberOfInputChannels(numberOfInputChannels), |
51 m_numberOfOutputChannels(numberOfOutputChannels), | 51 m_numberOfOutputChannels(numberOfOutputChannels), |
52 m_internalInputBus(AudioBus::create(numberOfInputChannels, | 52 m_internalInputBus(AudioBus::create(numberOfInputChannels, |
53 ProcessingSizeInFrames, | 53 ProcessingSizeInFrames, |
54 false)) { | 54 false)) { |
55 // Regardless of the allowed buffer sizes, we still need to process at the gra
nularity of the AudioNode. | 55 // Regardless of the allowed buffer sizes, we still need to process at the |
| 56 // granularity of the AudioNode. |
56 if (m_bufferSize < ProcessingSizeInFrames) | 57 if (m_bufferSize < ProcessingSizeInFrames) |
57 m_bufferSize = ProcessingSizeInFrames; | 58 m_bufferSize = ProcessingSizeInFrames; |
58 | 59 |
59 DCHECK_LE(numberOfInputChannels, BaseAudioContext::maxNumberOfChannels()); | 60 DCHECK_LE(numberOfInputChannels, BaseAudioContext::maxNumberOfChannels()); |
60 | 61 |
61 addInput(); | 62 addInput(); |
62 addOutput(numberOfOutputChannels); | 63 addOutput(numberOfOutputChannels); |
63 | 64 |
64 m_channelCount = numberOfInputChannels; | 65 m_channelCount = numberOfInputChannels; |
65 setInternalChannelCountMode(Explicit); | 66 setInternalChannelCountMode(Explicit); |
(...skipping 16 matching lines...) Expand all Loading... |
82 uninitialize(); | 83 uninitialize(); |
83 } | 84 } |
84 | 85 |
85 void ScriptProcessorHandler::initialize() { | 86 void ScriptProcessorHandler::initialize() { |
86 if (isInitialized()) | 87 if (isInitialized()) |
87 return; | 88 return; |
88 | 89 |
89 float sampleRate = context()->sampleRate(); | 90 float sampleRate = context()->sampleRate(); |
90 | 91 |
91 // Create double buffers on both the input and output sides. | 92 // Create double buffers on both the input and output sides. |
92 // These AudioBuffers will be directly accessed in the main thread by JavaScri
pt. | 93 // These AudioBuffers will be directly accessed in the main thread by |
| 94 // JavaScript. |
93 for (unsigned i = 0; i < 2; ++i) { | 95 for (unsigned i = 0; i < 2; ++i) { |
94 AudioBuffer* inputBuffer = | 96 AudioBuffer* inputBuffer = |
95 m_numberOfInputChannels ? AudioBuffer::create(m_numberOfInputChannels, | 97 m_numberOfInputChannels ? AudioBuffer::create(m_numberOfInputChannels, |
96 bufferSize(), sampleRate) | 98 bufferSize(), sampleRate) |
97 : 0; | 99 : 0; |
98 AudioBuffer* outputBuffer = | 100 AudioBuffer* outputBuffer = |
99 m_numberOfOutputChannels ? AudioBuffer::create(m_numberOfOutputChannels, | 101 m_numberOfOutputChannels ? AudioBuffer::create(m_numberOfOutputChannels, |
100 bufferSize(), sampleRate) | 102 bufferSize(), sampleRate) |
101 : 0; | 103 : 0; |
102 | 104 |
103 m_inputBuffers.append(inputBuffer); | 105 m_inputBuffers.append(inputBuffer); |
104 m_outputBuffers.append(outputBuffer); | 106 m_outputBuffers.append(outputBuffer); |
105 } | 107 } |
106 | 108 |
107 AudioHandler::initialize(); | 109 AudioHandler::initialize(); |
108 } | 110 } |
109 | 111 |
110 void ScriptProcessorHandler::process(size_t framesToProcess) { | 112 void ScriptProcessorHandler::process(size_t framesToProcess) { |
111 // Discussion about inputs and outputs: | 113 // Discussion about inputs and outputs: |
112 // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
and output (see inputBus and outputBus below). | 114 // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input |
113 // Additionally, there is a double-buffering for input and output which is exp
osed directly to JavaScript (see inputBuffer and outputBuffer below). | 115 // and output (see inputBus and outputBus below). Additionally, there is a |
114 // This node is the producer for inputBuffer and the consumer for outputBuffer
. | 116 // double-buffering for input and output which is exposed directly to |
115 // The JavaScript code is the consumer of inputBuffer and the producer for out
putBuffer. | 117 // JavaScript (see inputBuffer and outputBuffer below). This node is the |
| 118 // producer for inputBuffer and the consumer for outputBuffer. The JavaScript |
| 119 // code is the consumer of inputBuffer and the producer for outputBuffer. |
116 | 120 |
117 // Get input and output busses. | 121 // Get input and output busses. |
118 AudioBus* inputBus = input(0).bus(); | 122 AudioBus* inputBus = input(0).bus(); |
119 AudioBus* outputBus = output(0).bus(); | 123 AudioBus* outputBus = output(0).bus(); |
120 | 124 |
121 // Get input and output buffers. We double-buffer both the input and output si
des. | 125 // Get input and output buffers. We double-buffer both the input and output |
| 126 // sides. |
122 unsigned doubleBufferIndex = this->doubleBufferIndex(); | 127 unsigned doubleBufferIndex = this->doubleBufferIndex(); |
123 bool isDoubleBufferIndexGood = doubleBufferIndex < 2 && | 128 bool isDoubleBufferIndexGood = doubleBufferIndex < 2 && |
124 doubleBufferIndex < m_inputBuffers.size() && | 129 doubleBufferIndex < m_inputBuffers.size() && |
125 doubleBufferIndex < m_outputBuffers.size(); | 130 doubleBufferIndex < m_outputBuffers.size(); |
126 DCHECK(isDoubleBufferIndexGood); | 131 DCHECK(isDoubleBufferIndexGood); |
127 if (!isDoubleBufferIndexGood) | 132 if (!isDoubleBufferIndexGood) |
128 return; | 133 return; |
129 | 134 |
130 AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get(); | 135 AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get(); |
131 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); | 136 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); |
132 | 137 |
133 // Check the consistency of input and output buffers. | 138 // Check the consistency of input and output buffers. |
134 unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels(); | 139 unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels(); |
135 bool buffersAreGood = | 140 bool buffersAreGood = |
136 outputBuffer && bufferSize() == outputBuffer->length() && | 141 outputBuffer && bufferSize() == outputBuffer->length() && |
137 m_bufferReadWriteIndex + framesToProcess <= bufferSize(); | 142 m_bufferReadWriteIndex + framesToProcess <= bufferSize(); |
138 | 143 |
139 // If the number of input channels is zero, it's ok to have inputBuffer = 0. | 144 // If the number of input channels is zero, it's ok to have inputBuffer = 0. |
140 if (m_internalInputBus->numberOfChannels()) | 145 if (m_internalInputBus->numberOfChannels()) |
141 buffersAreGood = | 146 buffersAreGood = |
142 buffersAreGood && inputBuffer && bufferSize() == inputBuffer->length(); | 147 buffersAreGood && inputBuffer && bufferSize() == inputBuffer->length(); |
143 | 148 |
144 DCHECK(buffersAreGood); | 149 DCHECK(buffersAreGood); |
145 if (!buffersAreGood) | 150 if (!buffersAreGood) |
146 return; | 151 return; |
147 | 152 |
148 // We assume that bufferSize() is evenly divisible by framesToProcess - should
always be true, but we should still check. | 153 // We assume that bufferSize() is evenly divisible by framesToProcess - should |
| 154 // always be true, but we should still check. |
149 bool isFramesToProcessGood = framesToProcess && | 155 bool isFramesToProcessGood = framesToProcess && |
150 bufferSize() >= framesToProcess && | 156 bufferSize() >= framesToProcess && |
151 !(bufferSize() % framesToProcess); | 157 !(bufferSize() % framesToProcess); |
152 DCHECK(isFramesToProcessGood); | 158 DCHECK(isFramesToProcessGood); |
153 if (!isFramesToProcessGood) | 159 if (!isFramesToProcessGood) |
154 return; | 160 return; |
155 | 161 |
156 unsigned numberOfOutputChannels = outputBus->numberOfChannels(); | 162 unsigned numberOfOutputChannels = outputBus->numberOfChannels(); |
157 | 163 |
158 bool channelsAreGood = (numberOfInputChannels == m_numberOfInputChannels) && | 164 bool channelsAreGood = (numberOfInputChannels == m_numberOfInputChannels) && |
(...skipping 13 matching lines...) Expand all Loading... |
172 // Copy from the output buffer to the output. | 178 // Copy from the output buffer to the output. |
173 for (unsigned i = 0; i < numberOfOutputChannels; ++i) | 179 for (unsigned i = 0; i < numberOfOutputChannels; ++i) |
174 memcpy(outputBus->channel(i)->mutableData(), | 180 memcpy(outputBus->channel(i)->mutableData(), |
175 outputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, | 181 outputBuffer->getChannelData(i)->data() + m_bufferReadWriteIndex, |
176 sizeof(float) * framesToProcess); | 182 sizeof(float) * framesToProcess); |
177 | 183 |
178 // Update the buffering index. | 184 // Update the buffering index. |
179 m_bufferReadWriteIndex = | 185 m_bufferReadWriteIndex = |
180 (m_bufferReadWriteIndex + framesToProcess) % bufferSize(); | 186 (m_bufferReadWriteIndex + framesToProcess) % bufferSize(); |
181 | 187 |
182 // m_bufferReadWriteIndex will wrap back around to 0 when the current input an
d output buffers are full. | 188 // m_bufferReadWriteIndex will wrap back around to 0 when the current input |
| 189 // and output buffers are full. |
183 // When this happens, fire an event and swap buffers. | 190 // When this happens, fire an event and swap buffers. |
184 if (!m_bufferReadWriteIndex) { | 191 if (!m_bufferReadWriteIndex) { |
185 // Avoid building up requests on the main thread to fire process events when
they're not being handled. | 192 // Avoid building up requests on the main thread to fire process events when |
186 // This could be a problem if the main thread is very busy doing other thing
s and is being held up handling previous requests. | 193 // they're not being handled. This could be a problem if the main thread is |
187 // The audio thread can't block on this lock, so we call tryLock() instead. | 194 // very busy doing other things and is being held up handling previous |
| 195 // requests. The audio thread can't block on this lock, so we call |
| 196 // tryLock() instead. |
188 MutexTryLocker tryLocker(m_processEventLock); | 197 MutexTryLocker tryLocker(m_processEventLock); |
189 if (!tryLocker.locked()) { | 198 if (!tryLocker.locked()) { |
190 // We're late in handling the previous request. The main thread must be ve
ry busy. | 199 // We're late in handling the previous request. The main thread must be |
191 // The best we can do is clear out the buffer ourself here. | 200 // very busy. The best we can do is clear out the buffer ourself here. |
192 outputBuffer->zero(); | 201 outputBuffer->zero(); |
193 } else if (context()->getExecutionContext()) { | 202 } else if (context()->getExecutionContext()) { |
194 // With the realtime context, execute the script code asynchronously | 203 // With the realtime context, execute the script code asynchronously |
195 // and do not wait. | 204 // and do not wait. |
196 if (context()->hasRealtimeConstraint()) { | 205 if (context()->hasRealtimeConstraint()) { |
197 // Fire the event on the main thread with the appropriate buffer | 206 // Fire the event on the main thread with the appropriate buffer |
198 // index. | 207 // index. |
199 context()->getExecutionContext()->postTask( | 208 context()->getExecutionContext()->postTask( |
200 BLINK_FROM_HERE, | 209 BLINK_FROM_HERE, |
201 createCrossThreadTask(&ScriptProcessorHandler::fireProcessEvent, | 210 createCrossThreadTask(&ScriptProcessorHandler::fireProcessEvent, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); | 244 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); |
236 DCHECK(outputBuffer); | 245 DCHECK(outputBuffer); |
237 if (!outputBuffer) | 246 if (!outputBuffer) |
238 return; | 247 return; |
239 | 248 |
240 // Avoid firing the event if the document has already gone away. | 249 // Avoid firing the event if the document has already gone away. |
241 if (node() && context() && context()->getExecutionContext()) { | 250 if (node() && context() && context()->getExecutionContext()) { |
242 // This synchronizes with process(). | 251 // This synchronizes with process(). |
243 MutexLocker processLocker(m_processEventLock); | 252 MutexLocker processLocker(m_processEventLock); |
244 | 253 |
245 // Calculate a playbackTime with the buffersize which needs to be processed
each time onaudioprocess is called. | 254 // Calculate a playbackTime with the buffersize which needs to be processed |
246 // The outputBuffer being passed to JS will be played after exhuasting previ
ous outputBuffer by double-buffering. | 255 // each time onaudioprocess is called. The outputBuffer being passed to JS |
| 256 // will be played after exhuasting previous outputBuffer by |
| 257 // double-buffering. |
247 double playbackTime = (context()->currentSampleFrame() + m_bufferSize) / | 258 double playbackTime = (context()->currentSampleFrame() + m_bufferSize) / |
248 static_cast<double>(context()->sampleRate()); | 259 static_cast<double>(context()->sampleRate()); |
249 | 260 |
250 // Call the JavaScript event handler which will do the audio processing. | 261 // Call the JavaScript event handler which will do the audio processing. |
251 node()->dispatchEvent( | 262 node()->dispatchEvent( |
252 AudioProcessingEvent::create(inputBuffer, outputBuffer, playbackTime)); | 263 AudioProcessingEvent::create(inputBuffer, outputBuffer, playbackTime)); |
253 } | 264 } |
254 } | 265 } |
255 | 266 |
256 void ScriptProcessorHandler::fireProcessEventForOfflineAudioContext( | 267 void ScriptProcessorHandler::fireProcessEventForOfflineAudioContext( |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 size_t bufferSize, | 336 size_t bufferSize, |
326 unsigned numberOfInputChannels, | 337 unsigned numberOfInputChannels, |
327 unsigned numberOfOutputChannels) | 338 unsigned numberOfOutputChannels) |
328 : AudioNode(context), ActiveScriptWrappable(this) { | 339 : AudioNode(context), ActiveScriptWrappable(this) { |
329 setHandler(ScriptProcessorHandler::create(*this, sampleRate, bufferSize, | 340 setHandler(ScriptProcessorHandler::create(*this, sampleRate, bufferSize, |
330 numberOfInputChannels, | 341 numberOfInputChannels, |
331 numberOfOutputChannels)); | 342 numberOfOutputChannels)); |
332 } | 343 } |
333 | 344 |
334 static size_t chooseBufferSize() { | 345 static size_t chooseBufferSize() { |
335 // Choose a buffer size based on the audio hardware buffer size. Arbitarily ma
ke it a power of | 346 // Choose a buffer size based on the audio hardware buffer size. Arbitarily |
336 // two that is 4 times greater than the hardware buffer size. | 347 // make it a power of two that is 4 times greater than the hardware buffer |
| 348 // size. |
337 // FIXME: What is the best way to choose this? | 349 // FIXME: What is the best way to choose this? |
338 size_t hardwareBufferSize = Platform::current()->audioHardwareBufferSize(); | 350 size_t hardwareBufferSize = Platform::current()->audioHardwareBufferSize(); |
339 size_t bufferSize = | 351 size_t bufferSize = |
340 1 << static_cast<unsigned>(log2(4 * hardwareBufferSize) + 0.5); | 352 1 << static_cast<unsigned>(log2(4 * hardwareBufferSize) + 0.5); |
341 | 353 |
342 if (bufferSize < 256) | 354 if (bufferSize < 256) |
343 return 256; | 355 return 256; |
344 if (bufferSize > 16384) | 356 if (bufferSize > 16384) |
345 return 16384; | 357 return 16384; |
346 | 358 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 | 473 |
462 // If |onaudioprocess| event handler is defined, the node should not be | 474 // If |onaudioprocess| event handler is defined, the node should not be |
463 // GCed even if it is out of scope. | 475 // GCed even if it is out of scope. |
464 if (hasEventListeners(EventTypeNames::audioprocess)) | 476 if (hasEventListeners(EventTypeNames::audioprocess)) |
465 return true; | 477 return true; |
466 | 478 |
467 return false; | 479 return false; |
468 } | 480 } |
469 | 481 |
470 } // namespace blink | 482 } // namespace blink |
OLD | NEW |