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 |