| 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 86 |
| 87 return adoptRef(new ScriptProcessorNode(context, sampleRate, bufferSize, num
berOfInputChannels, numberOfOutputChannels)); | 87 return adoptRef(new ScriptProcessorNode(context, sampleRate, bufferSize, num
berOfInputChannels, numberOfOutputChannels)); |
| 88 } | 88 } |
| 89 | 89 |
| 90 ScriptProcessorNode::ScriptProcessorNode(AudioContext* context, float sampleRate
, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChan
nels) | 90 ScriptProcessorNode::ScriptProcessorNode(AudioContext* context, float sampleRate
, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChan
nels) |
| 91 : AudioNode(context, sampleRate) | 91 : AudioNode(context, sampleRate) |
| 92 , m_doubleBufferIndex(0) | 92 , m_doubleBufferIndex(0) |
| 93 , m_doubleBufferIndexForEvent(0) | 93 , m_doubleBufferIndexForEvent(0) |
| 94 , m_bufferSize(bufferSize) | 94 , m_bufferSize(bufferSize) |
| 95 , m_bufferReadWriteIndex(0) | 95 , m_bufferReadWriteIndex(0) |
| 96 , m_isRequestOutstanding(false) | |
| 97 , m_numberOfInputChannels(numberOfInputChannels) | 96 , m_numberOfInputChannels(numberOfInputChannels) |
| 98 , m_numberOfOutputChannels(numberOfOutputChannels) | 97 , m_numberOfOutputChannels(numberOfOutputChannels) |
| 99 , m_internalInputBus(AudioBus::create(numberOfInputChannels, AudioNode::Proc
essingSizeInFrames, false)) | 98 , m_internalInputBus(AudioBus::create(numberOfInputChannels, AudioNode::Proc
essingSizeInFrames, false)) |
| 100 { | 99 { |
| 101 ScriptWrappable::init(this); | 100 ScriptWrappable::init(this); |
| 102 // Regardless of the allowed buffer sizes, we still need to process at the g
ranularity of the AudioNode. | 101 // Regardless of the allowed buffer sizes, we still need to process at the g
ranularity of the AudioNode. |
| 103 if (m_bufferSize < AudioNode::ProcessingSizeInFrames) | 102 if (m_bufferSize < AudioNode::ProcessingSizeInFrames) |
| 104 m_bufferSize = AudioNode::ProcessingSizeInFrames; | 103 m_bufferSize = AudioNode::ProcessingSizeInFrames; |
| 105 | 104 |
| 106 ASSERT(numberOfInputChannels <= AudioContext::maxNumberOfChannels()); | 105 ASSERT(numberOfInputChannels <= AudioContext::maxNumberOfChannels()); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 memcpy(outputBus->channel(i)->mutableData(), outputBuffer->getChannelDat
a(i)->data() + m_bufferReadWriteIndex, sizeof(float) * framesToProcess); | 206 memcpy(outputBus->channel(i)->mutableData(), outputBuffer->getChannelDat
a(i)->data() + m_bufferReadWriteIndex, sizeof(float) * framesToProcess); |
| 208 | 207 |
| 209 // Update the buffering index. | 208 // Update the buffering index. |
| 210 m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % buffer
Size(); | 209 m_bufferReadWriteIndex = (m_bufferReadWriteIndex + framesToProcess) % buffer
Size(); |
| 211 | 210 |
| 212 // m_bufferReadWriteIndex will wrap back around to 0 when the current input
and output buffers are full. | 211 // m_bufferReadWriteIndex will wrap back around to 0 when the current input
and output buffers are full. |
| 213 // When this happens, fire an event and swap buffers. | 212 // When this happens, fire an event and swap buffers. |
| 214 if (!m_bufferReadWriteIndex) { | 213 if (!m_bufferReadWriteIndex) { |
| 215 // Avoid building up requests on the main thread to fire process events
when they're not being handled. | 214 // Avoid building up requests on the main thread to fire process events
when they're not being handled. |
| 216 // This could be a problem if the main thread is very busy doing other t
hings and is being held up handling previous requests. | 215 // This could be a problem if the main thread is very busy doing other t
hings and is being held up handling previous requests. |
| 217 if (m_isRequestOutstanding) { | 216 // The audio thread can't block on this lock, so we call tryLock() inste
ad. |
| 217 MutexTryLocker tryLocker(m_processEventLock); |
| 218 if (!tryLocker.locked()) { |
| 218 // We're late in handling the previous request. The main thread must
be very busy. | 219 // We're late in handling the previous request. The main thread must
be very busy. |
| 219 // The best we can do is clear out the buffer ourself here. | 220 // The best we can do is clear out the buffer ourself here. |
| 220 outputBuffer->zero(); | 221 outputBuffer->zero(); |
| 221 } else { | 222 } else { |
| 222 // Reference ourself so we don't accidentally get deleted before fir
eProcessEvent() gets called. | 223 // Reference ourself so we don't accidentally get deleted before fir
eProcessEvent() gets called. |
| 223 ref(); | 224 ref(); |
| 224 | 225 |
| 225 // Fire the event on the main thread, not this one (which is the rea
ltime audio thread). | 226 // Fire the event on the main thread, not this one (which is the rea
ltime audio thread). |
| 226 m_doubleBufferIndexForEvent = m_doubleBufferIndex; | 227 m_doubleBufferIndexForEvent = m_doubleBufferIndex; |
| 227 m_isRequestOutstanding = true; | |
| 228 callOnMainThread(fireProcessEventDispatch, this); | 228 callOnMainThread(fireProcessEventDispatch, this); |
| 229 } | 229 } |
| 230 | 230 |
| 231 swapBuffers(); | 231 swapBuffers(); |
| 232 } | 232 } |
| 233 } | 233 } |
| 234 | 234 |
| 235 void ScriptProcessorNode::fireProcessEventDispatch(void* userData) | 235 void ScriptProcessorNode::fireProcessEventDispatch(void* userData) |
| 236 { | 236 { |
| 237 ScriptProcessorNode* jsAudioNode = static_cast<ScriptProcessorNode*>(userDat
a); | 237 ScriptProcessorNode* jsAudioNode = static_cast<ScriptProcessorNode*>(userDat
a); |
| 238 ASSERT(jsAudioNode); | 238 ASSERT(jsAudioNode); |
| 239 if (!jsAudioNode) | 239 if (!jsAudioNode) |
| 240 return; | 240 return; |
| 241 | 241 |
| 242 jsAudioNode->fireProcessEvent(); | 242 jsAudioNode->fireProcessEvent(); |
| 243 | 243 |
| 244 // De-reference to match the ref() call in process(). | 244 // De-reference to match the ref() call in process(). |
| 245 jsAudioNode->deref(); | 245 jsAudioNode->deref(); |
| 246 } | 246 } |
| 247 | 247 |
| 248 void ScriptProcessorNode::fireProcessEvent() | 248 void ScriptProcessorNode::fireProcessEvent() |
| 249 { | 249 { |
| 250 ASSERT(isMainThread() && m_isRequestOutstanding); | 250 ASSERT(isMainThread()); |
| 251 | 251 |
| 252 bool isIndexGood = m_doubleBufferIndexForEvent < 2; | 252 bool isIndexGood = m_doubleBufferIndexForEvent < 2; |
| 253 ASSERT(isIndexGood); | 253 ASSERT(isIndexGood); |
| 254 if (!isIndexGood) | 254 if (!isIndexGood) |
| 255 return; | 255 return; |
| 256 | 256 |
| 257 AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get()
; | 257 AudioBuffer* inputBuffer = m_inputBuffers[m_doubleBufferIndexForEvent].get()
; |
| 258 AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get
(); | 258 AudioBuffer* outputBuffer = m_outputBuffers[m_doubleBufferIndexForEvent].get
(); |
| 259 ASSERT(outputBuffer); | 259 ASSERT(outputBuffer); |
| 260 if (!outputBuffer) | 260 if (!outputBuffer) |
| 261 return; | 261 return; |
| 262 | 262 |
| 263 // Avoid firing the event if the document has already gone away. | 263 // Avoid firing the event if the document has already gone away. |
| 264 if (context()->executionContext()) { | 264 if (context()->executionContext()) { |
| 265 // Let the audio thread know we've gotten to the point where it's OK for
it to make another request. | 265 // This synchronizes with process(). |
| 266 m_isRequestOutstanding = false; | 266 MutexLocker processLocker(m_processEventLock); |
| 267 | 267 |
| 268 // Call the JavaScript event handler which will do the audio processing. | 268 // Call the JavaScript event handler which will do the audio processing. |
| 269 dispatchEvent(AudioProcessingEvent::create(inputBuffer, outputBuffer)); | 269 dispatchEvent(AudioProcessingEvent::create(inputBuffer, outputBuffer)); |
| 270 } | 270 } |
| 271 } | 271 } |
| 272 | 272 |
| 273 double ScriptProcessorNode::tailTime() const | 273 double ScriptProcessorNode::tailTime() const |
| 274 { | 274 { |
| 275 return std::numeric_limits<double>::infinity(); | 275 return std::numeric_limits<double>::infinity(); |
| 276 } | 276 } |
| 277 | 277 |
| 278 double ScriptProcessorNode::latencyTime() const | 278 double ScriptProcessorNode::latencyTime() const |
| 279 { | 279 { |
| 280 return std::numeric_limits<double>::infinity(); | 280 return std::numeric_limits<double>::infinity(); |
| 281 } | 281 } |
| 282 | 282 |
| 283 } // namespace WebCore | 283 } // namespace WebCore |
| 284 | 284 |
| 285 #endif // ENABLE(WEB_AUDIO) | 285 #endif // ENABLE(WEB_AUDIO) |
| OLD | NEW |