| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 AudioNode::uninitialize(); | 132 AudioNode::uninitialize(); |
| 133 } | 133 } |
| 134 | 134 |
| 135 void ScriptProcessorNode::process(size_t framesToProcess) | 135 void ScriptProcessorNode::process(size_t framesToProcess) |
| 136 { | 136 { |
| 137 // Discussion about inputs and outputs: | 137 // Discussion about inputs and outputs: |
| 138 // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its inpu
t and output (see inputBus and outputBus below). | 138 // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its inpu
t and output (see inputBus and outputBus below). |
| 139 // Additionally, there is a double-buffering for input and output which is e
xposed directly to JavaScript (see inputBuffer and outputBuffer below). | 139 // Additionally, there is a double-buffering for input and output which is e
xposed directly to JavaScript (see inputBuffer and outputBuffer below). |
| 140 // This node is the producer for inputBuffer and the consumer for outputBuff
er. | 140 // This node is the producer for inputBuffer and the consumer for outputBuff
er. |
| 141 // The JavaScript code is the consumer of inputBuffer and the producer for o
utputBuffer. | 141 // The JavaScript code is the consumer of inputBuffer and the producer for o
utputBuffer. |
| 142 | 142 |
| 143 // Get input and output busses. | 143 // Get input and output busses. |
| 144 AudioBus* inputBus = this->input(0)->bus(); | 144 AudioBus* inputBus = this->input(0)->bus(); |
| 145 AudioBus* outputBus = this->output(0)->bus(); | 145 AudioBus* outputBus = this->output(0)->bus(); |
| 146 | 146 |
| 147 // Get input and output buffers. We double-buffer both the input and output
sides. | 147 // Get input and output buffers. We double-buffer both the input and output
sides. |
| 148 unsigned doubleBufferIndex = this->doubleBufferIndex(); | 148 unsigned doubleBufferIndex = this->doubleBufferIndex(); |
| 149 bool isDoubleBufferIndexGood = doubleBufferIndex < 2 && doubleBufferIndex <
m_inputBuffers.size() && doubleBufferIndex < m_outputBuffers.size(); | 149 bool isDoubleBufferIndexGood = doubleBufferIndex < 2 && doubleBufferIndex <
m_inputBuffers.size() && doubleBufferIndex < m_outputBuffers.size(); |
| 150 ASSERT(isDoubleBufferIndexGood); | 150 ASSERT(isDoubleBufferIndexGood); |
| 151 if (!isDoubleBufferIndexGood) | 151 if (!isDoubleBufferIndexGood) |
| 152 return; | 152 return; |
| 153 | 153 |
| 154 AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get(); | 154 AudioBuffer* inputBuffer = m_inputBuffers[doubleBufferIndex].get(); |
| 155 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); | 155 AudioBuffer* outputBuffer = m_outputBuffers[doubleBufferIndex].get(); |
| 156 | 156 |
| 157 // Check the consistency of input and output buffers. | 157 // Check the consistency of input and output buffers. |
| 158 unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels(); | 158 unsigned numberOfInputChannels = m_internalInputBus->numberOfChannels(); |
| 159 bool buffersAreGood = outputBuffer && bufferSize() == outputBuffer->length()
&& m_bufferReadWriteIndex + framesToProcess <= bufferSize(); | 159 bool buffersAreGood = outputBuffer && bufferSize() == outputBuffer->length()
&& m_bufferReadWriteIndex + framesToProcess <= bufferSize(); |
| 160 | 160 |
| 161 // If the number of input channels is zero, it's ok to have inputBuffer = 0. | 161 // If the number of input channels is zero, it's ok to have inputBuffer = 0. |
| 162 if (m_internalInputBus->numberOfChannels()) | 162 if (m_internalInputBus->numberOfChannels()) |
| 163 buffersAreGood = buffersAreGood && inputBuffer && bufferSize() == inputB
uffer->length(); | 163 buffersAreGood = buffersAreGood && inputBuffer && bufferSize() == inputB
uffer->length(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 178 ASSERT(channelsAreGood); | 178 ASSERT(channelsAreGood); |
| 179 if (!channelsAreGood) | 179 if (!channelsAreGood) |
| 180 return; | 180 return; |
| 181 | 181 |
| 182 for (unsigned i = 0; i < numberOfInputChannels; i++) | 182 for (unsigned i = 0; i < numberOfInputChannels; i++) |
| 183 m_internalInputBus->setChannelMemory(i, inputBuffer->getChannelData(i)->
data() + m_bufferReadWriteIndex, framesToProcess); | 183 m_internalInputBus->setChannelMemory(i, inputBuffer->getChannelData(i)->
data() + m_bufferReadWriteIndex, framesToProcess); |
| 184 | 184 |
| 185 if (numberOfInputChannels) | 185 if (numberOfInputChannels) |
| 186 m_internalInputBus->copyFrom(*inputBus); | 186 m_internalInputBus->copyFrom(*inputBus); |
| 187 | 187 |
| 188 // Copy from the output buffer to the output. | 188 // Copy from the output buffer to the output. |
| 189 for (unsigned i = 0; i < numberOfOutputChannels; ++i) | 189 for (unsigned i = 0; i < numberOfOutputChannels; ++i) |
| 190 memcpy(outputBus->channel(i)->mutableData(), outputBuffer->getChannelDat
a(i)->data() + m_bufferReadWriteIndex, sizeof(float) * framesToProcess); | 190 memcpy(outputBus->channel(i)->mutableData(), outputBuffer->getChannelDat
a(i)->data() + m_bufferReadWriteIndex, sizeof(float) * framesToProcess); |
| 191 | 191 |
| 192 // Update the buffering index. | 192 // Update the buffering index. |
| 193 m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % buffer
Size(); | 193 m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % buffer
Size(); |
| 194 | 194 |
| 195 // m_bufferReadWriteIndex will wrap back around to 0 when the current input
and output buffers are full. | 195 // m_bufferReadWriteIndex will wrap back around to 0 when the current input
and output buffers are full. |
| 196 // When this happens, fire an event and swap buffers. | 196 // When this happens, fire an event and swap buffers. |
| 197 if (!m_bufferReadWriteIndex) { | 197 if (!m_bufferReadWriteIndex) { |
| 198 // Avoid building up requests on the main thread to fire process events
when they're not being handled. | 198 // Avoid building up requests on the main thread to fire process events
when they're not being handled. |
| 199 // This could be a problem if the main thread is very busy doing other t
hings and is being held up handling previous requests. | 199 // This could be a problem if the main thread is very busy doing other t
hings and is being held up handling previous requests. |
| 200 if (m_isRequestOutstanding) { | 200 if (m_isRequestOutstanding) { |
| 201 // We're late in handling the previous request. The main thread must
be very busy. | 201 // We're late in handling the previous request. The main thread must
be very busy. |
| 202 // The best we can do is clear out the buffer ourself here. | 202 // The best we can do is clear out the buffer ourself here. |
| 203 outputBuffer->zero(); | 203 outputBuffer->zero(); |
| 204 } else { | 204 } else { |
| 205 // Reference ourself so we don't accidentally get deleted before fir
eProcessEvent() gets called. | 205 // Reference ourself so we don't accidentally get deleted before fir
eProcessEvent() gets called. |
| 206 ref(); | 206 ref(); |
| 207 | 207 |
| 208 // Fire the event on the main thread, not this one (which is the rea
ltime audio thread). | 208 // Fire the event on the main thread, not this one (which is the rea
ltime audio thread). |
| 209 m_doubleBufferIndexForEvent = m_doubleBufferIndex; | 209 m_doubleBufferIndexForEvent = m_doubleBufferIndex; |
| 210 m_isRequestOutstanding = true; | 210 m_isRequestOutstanding = true; |
| 211 callOnMainThread(fireProcessEventDispatch, this); | 211 callOnMainThread(fireProcessEventDispatch, this); |
| 212 } | 212 } |
| 213 | 213 |
| 214 swapBuffers(); | 214 swapBuffers(); |
| 215 } | 215 } |
| 216 } | 216 } |
| 217 | 217 |
| 218 void ScriptProcessorNode::fireProcessEventDispatch(void* userData) | 218 void ScriptProcessorNode::fireProcessEventDispatch(void* userData) |
| 219 { | 219 { |
| 220 ScriptProcessorNode* jsAudioNode = static_cast<ScriptProcessorNode*>(userDat
a); | 220 ScriptProcessorNode* jsAudioNode = static_cast<ScriptProcessorNode*>(userDat
a); |
| 221 ASSERT(jsAudioNode); | 221 ASSERT(jsAudioNode); |
| 222 if (!jsAudioNode) | 222 if (!jsAudioNode) |
| 223 return; | 223 return; |
| 224 | 224 |
| 225 jsAudioNode->fireProcessEvent(); | 225 jsAudioNode->fireProcessEvent(); |
| 226 | 226 |
| 227 // De-reference to match the ref() call in process(). | 227 // De-reference to match the ref() call in process(). |
| 228 jsAudioNode->deref(); | 228 jsAudioNode->deref(); |
| 229 } | 229 } |
| 230 | 230 |
| 231 void ScriptProcessorNode::fireProcessEvent() | 231 void ScriptProcessorNode::fireProcessEvent() |
| 232 { | 232 { |
| 233 ASSERT(isMainThread() && m_isRequestOutstanding); | 233 ASSERT(isMainThread() && m_isRequestOutstanding); |
| 234 | 234 |
| 235 bool isIndexGood = m_doubleBufferIndexForEvent < 2; | 235 bool isIndexGood = m_doubleBufferIndexForEvent < 2; |
| 236 ASSERT(isIndexGood); | 236 ASSERT(isIndexGood); |
| 237 if (!isIndexGood) | 237 if (!isIndexGood) |
| 238 return; | 238 return; |
| 239 | 239 |
| 240 AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get()
; | 240 AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get()
; |
| 241 AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get
(); | 241 AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get
(); |
| 242 ASSERT(outputBuffer); | 242 ASSERT(outputBuffer); |
| 243 if (!outputBuffer) | 243 if (!outputBuffer) |
| 244 return; | 244 return; |
| 245 | 245 |
| 246 // Avoid firing the event if the document has already gone away. | 246 // Avoid firing the event if the document has already gone away. |
| 247 if (context()->scriptExecutionContext()) { | 247 if (context()->scriptExecutionContext()) { |
| 248 // Let the audio thread know we've gotten to the point where it's OK for
it to make another request. | 248 // Let the audio thread know we've gotten to the point where it's OK for
it to make another request. |
| 249 m_isRequestOutstanding = false; | 249 m_isRequestOutstanding = false; |
| 250 | 250 |
| 251 // Call the JavaScript event handler which will do the audio processing. | 251 // Call the JavaScript event handler which will do the audio processing. |
| 252 dispatchEvent(AudioProcessingEvent::create(inputBuffer, outputBuffer)); | 252 dispatchEvent(AudioProcessingEvent::create(inputBuffer, outputBuffer)); |
| 253 } | 253 } |
| 254 } | 254 } |
| 255 | 255 |
| 256 void ScriptProcessorNode::reset() | 256 void ScriptProcessorNode::reset() |
| 257 { | 257 { |
| 258 m_bufferReadWriteIndex = 0; | 258 m_bufferReadWriteIndex = 0; |
| 259 m_doubleBufferIndex = 0; | 259 m_doubleBufferIndex = 0; |
| 260 | 260 |
| 261 for (unsigned i = 0; i < 2; ++i) { | 261 for (unsigned i = 0; i < 2; ++i) { |
| 262 m_inputBuffers[i]->zero(); | 262 m_inputBuffers[i]->zero(); |
| 263 m_outputBuffers[i]->zero(); | 263 m_outputBuffers[i]->zero(); |
| 264 } | 264 } |
| 265 } | 265 } |
| 266 | 266 |
| 267 double ScriptProcessorNode::tailTime() const | 267 double ScriptProcessorNode::tailTime() const |
| 268 { | 268 { |
| 269 return std::numeric_limits<double>::infinity(); | 269 return std::numeric_limits<double>::infinity(); |
| 270 } | 270 } |
| 271 | 271 |
| 272 double ScriptProcessorNode::latencyTime() const | 272 double ScriptProcessorNode::latencyTime() const |
| 273 { | 273 { |
| 274 return std::numeric_limits<double>::infinity(); | 274 return std::numeric_limits<double>::infinity(); |
| 275 } | 275 } |
| 276 | 276 |
| 277 } // namespace WebCore | 277 } // namespace WebCore |
| 278 | 278 |
| 279 #endif // ENABLE(WEB_AUDIO) | 279 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |