Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: Source/modules/webaudio/ScriptProcessorNode.cpp

Issue 212183002: Fix potential thread safety issue on ScriptProcessNdoe during fire onaudioprocess eventhandler. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/modules/webaudio/ScriptProcessorNode.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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)
OLDNEW
« no previous file with comments | « Source/modules/webaudio/ScriptProcessorNode.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698