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

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

Issue 196993002: Guarantee a thread safety when accessing source location info in pannerNode. (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/PannerNode.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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 , m_panningModel(Panner::PanningModelHRTF) 51 , m_panningModel(Panner::PanningModelHRTF)
52 , m_position(0, 0, 0) 52 , m_position(0, 0, 0)
53 , m_orientation(1, 0, 0) 53 , m_orientation(1, 0, 0)
54 , m_velocity(0, 0, 0) 54 , m_velocity(0, 0, 0)
55 , m_cachedPosition(0, 0, 0) 55 , m_cachedPosition(0, 0, 0)
56 , m_cachedOrientation(1, 0, 0) 56 , m_cachedOrientation(1, 0, 0)
57 , m_cachedVelocity(0, 0, 0) 57 , m_cachedVelocity(0, 0, 0)
58 , m_lastGain(-1.0) 58 , m_lastGain(-1.0)
59 , m_cachedAzimuth(0) 59 , m_cachedAzimuth(0)
60 , m_cachedElevation(0) 60 , m_cachedElevation(0)
61 , m_cachedDistanceConeGain(0) 61 , m_cachedDistanceConeGain(1.0f)
62 , m_cachedDopplerRate(1) 62 , m_cachedDopplerRate(1)
63 , m_connectionCount(0) 63 , m_connectionCount(0)
64 { 64 {
65 // Load the HRTF database asynchronously so we don't block the Javascript th read while creating the HRTF database. 65 // Load the HRTF database asynchronously so we don't block the Javascript th read while creating the HRTF database.
66 // The HRTF panner will return zeroes until the database is loaded. 66 // The HRTF panner will return zeroes until the database is loaded.
67 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece ssary(context->sampleRate()); 67 m_hrtfDatabaseLoader = HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNece ssary(context->sampleRate());
68 68
69 ScriptWrappable::init(this); 69 ScriptWrappable::init(this);
70 addInput(adoptPtr(new AudioNodeInput(this))); 70 addInput(adoptPtr(new AudioNodeInput(this)));
71 addOutput(adoptPtr(new AudioNodeOutput(this, 2))); 71 addOutput(adoptPtr(new AudioNodeOutput(this, 2)));
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 destination->zero(); 116 destination->zero();
117 return; 117 return;
118 } 118 }
119 119
120 AudioBus* source = input(0)->bus(); 120 AudioBus* source = input(0)->bus();
121 if (!source) { 121 if (!source) {
122 destination->zero(); 122 destination->zero();
123 return; 123 return;
124 } 124 }
125 125
126 // HRTFDatabase should be loaded before proceeding for offline audio context when panningModel() is "HRTF". 126 // The audio thread can't block on this lock, so we call tryLock() instead.
127 if (panningModel() == "HRTF" && !m_hrtfDatabaseLoader->isLoaded()) { 127 MutexTryLocker tryLocker(m_processLock);
128 if (context()->isOfflineContext()) { 128 if (tryLocker.locked()) {
129 m_hrtfDatabaseLoader->waitForLoaderThreadCompletion(); 129 // HRTFDatabase should be loaded before proceeding for offline audio con text when panningModel() is "HRTF".
130 } else { 130 if (panningModel() == "HRTF" && !m_hrtfDatabaseLoader->isLoaded()) {
131 destination->zero(); 131 if (context()->isOfflineContext()) {
132 return; 132 m_hrtfDatabaseLoader->waitForLoaderThreadCompletion();
133 } else {
134 destination->zero();
135 return;
136 }
133 } 137 }
134 }
135 138
136 // The audio thread can't block on this lock, so we call tryLock() instead.
137 MutexTryLocker tryLocker(m_pannerLock);
138 if (tryLocker.locked()) {
139 // Apply the panning effect. 139 // Apply the panning effect.
140 double azimuth; 140 double azimuth;
141 double elevation; 141 double elevation;
142 azimuthElevation(&azimuth, &elevation); 142 azimuthElevation(&azimuth, &elevation);
143 143
144 m_panner->pan(azimuth, elevation, source, destination, framesToProcess); 144 m_panner->pan(azimuth, elevation, source, destination, framesToProcess);
145 145
146 // Get the distance and cone gain. 146 // Get the distance and cone gain.
147 float totalGain = distanceConeGain(); 147 float totalGain = distanceConeGain();
148 148
149 // Snap to desired gain at the beginning. 149 // Snap to desired gain at the beginning.
150 if (m_lastGain == -1.0) 150 if (m_lastGain == -1.0)
151 m_lastGain = totalGain; 151 m_lastGain = totalGain;
152 152
153 // Apply gain in-place with de-zippering. 153 // Apply gain in-place with de-zippering.
154 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain); 154 destination->copyWithGainFrom(*destination, &m_lastGain, totalGain);
155 155
156 // Update the cached listener in case listener has moved. 156 // Update the cached listener in case listener has moved.
157 updateCachedListener(); 157 updateCachedListener();
158 // Now update the cached source location in case the source has changed. 158 // Now update the cached source location in case the source has changed.
159 updateCachedSourceLocationInfo(); 159 updateCachedSourceLocationInfo();
160 } else { 160 } else {
161 // Too bad - The tryLock() failed. We must be in the middle of changing the panner. 161 // Too bad - The tryLock() failed.
162 // We must be in the middle of changing the panning model, the distance model, or the source's location information.
162 destination->zero(); 163 destination->zero();
163 } 164 }
164 } 165 }
165 166
166 void PannerNode::initialize() 167 void PannerNode::initialize()
167 { 168 {
168 if (isInitialized()) 169 if (isInitialized())
169 return; 170 return;
170 171
171 m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader .get()); 172 m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader .get());
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 ASSERT_NOT_REACHED(); 211 ASSERT_NOT_REACHED();
211 } 212 }
212 213
213 bool PannerNode::setPanningModel(unsigned model) 214 bool PannerNode::setPanningModel(unsigned model)
214 { 215 {
215 switch (model) { 216 switch (model) {
216 case EQUALPOWER: 217 case EQUALPOWER:
217 case HRTF: 218 case HRTF:
218 if (!m_panner.get() || model != m_panningModel) { 219 if (!m_panner.get() || model != m_panningModel) {
219 // This synchronizes with process(). 220 // This synchronizes with process().
220 MutexLocker processLocker(m_pannerLock); 221 MutexLocker processLocker(m_processLock);
221 222
222 OwnPtr<Panner> newPanner = Panner::create(model, sampleRate(), m_hrt fDatabaseLoader.get()); 223 OwnPtr<Panner> newPanner = Panner::create(model, sampleRate(), m_hrt fDatabaseLoader.get());
223 m_panner = newPanner.release(); 224 m_panner = newPanner.release();
224 m_panningModel = model; 225 m_panningModel = model;
225 } 226 }
226 break; 227 break;
227 default: 228 default:
228 return false; 229 return false;
229 } 230 }
230 231
231 return true; 232 return true;
232 } 233 }
233 234
234 void PannerNode::setPosition(float x, float y, float z) 235 void PannerNode::setPosition(float x, float y, float z)
235 { 236 {
236 // FIXME : consider thread safety about m_position in audio thread.
237 // See http://crbugs.com/350583.
238 FloatPoint3D position = FloatPoint3D(x, y, z); 237 FloatPoint3D position = FloatPoint3D(x, y, z);
239 238
240 if (m_position == position) 239 if (m_position == position)
241 return; 240 return;
242 241
242 // This synchronizes with process().
243 MutexLocker processLocker(m_processLock);
244
243 m_position = position; 245 m_position = position;
244 } 246 }
245 247
246 void PannerNode::setOrientation(float x, float y, float z) 248 void PannerNode::setOrientation(float x, float y, float z)
247 { 249 {
248 // FIXME : consider thread safety about m_orientation in audio thread.
249 // See http://crbugs.com/350583.
250 FloatPoint3D orientation = FloatPoint3D(x, y, z); 250 FloatPoint3D orientation = FloatPoint3D(x, y, z);
251 251
252 if (m_orientation == orientation) 252 if (m_orientation == orientation)
253 return; 253 return;
254 254
255 // This synchronizes with process().
256 MutexLocker processLocker(m_processLock);
257
255 m_orientation = orientation; 258 m_orientation = orientation;
256 } 259 }
257 260
258 void PannerNode::setVelocity(float x, float y, float z) 261 void PannerNode::setVelocity(float x, float y, float z)
259 { 262 {
260 // FIXME : consider thread safety about m_velocity in audio thread.
261 // See http://crbugs.com/350583.
262 FloatPoint3D velocity = FloatPoint3D(x, y, z); 263 FloatPoint3D velocity = FloatPoint3D(x, y, z);
263 264
264 if (m_velocity == velocity) 265 if (m_velocity == velocity)
265 return; 266 return;
266 267
268 // This synchronizes with process().
269 MutexLocker processLocker(m_processLock);
270
267 m_velocity = velocity; 271 m_velocity = velocity;
268 } 272 }
269 273
270 String PannerNode::distanceModel() const 274 String PannerNode::distanceModel() const
271 { 275 {
272 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) { 276 switch (const_cast<PannerNode*>(this)->m_distanceEffect.model()) {
273 case DistanceEffect::ModelLinear: 277 case DistanceEffect::ModelLinear:
274 return "linear"; 278 return "linear";
275 case DistanceEffect::ModelInverse: 279 case DistanceEffect::ModelInverse:
276 return "inverse"; 280 return "inverse";
(...skipping 16 matching lines...) Expand all
293 else 297 else
294 ASSERT_NOT_REACHED(); 298 ASSERT_NOT_REACHED();
295 } 299 }
296 300
297 bool PannerNode::setDistanceModel(unsigned model) 301 bool PannerNode::setDistanceModel(unsigned model)
298 { 302 {
299 switch (model) { 303 switch (model) {
300 case DistanceEffect::ModelLinear: 304 case DistanceEffect::ModelLinear:
301 case DistanceEffect::ModelInverse: 305 case DistanceEffect::ModelInverse:
302 case DistanceEffect::ModelExponential: 306 case DistanceEffect::ModelExponential:
303 m_distanceEffect.setModel(static_cast<DistanceEffect::ModelType>(model), true); 307 if (model != m_distanceEffect.model()) {
308 // This synchronizes with process().
309 MutexLocker processLocker(m_processLock);
310 m_distanceEffect.setModel(static_cast<DistanceEffect::ModelType>(mod el), true);
311 }
304 break; 312 break;
305 default: 313 default:
306 return false; 314 return false;
307 } 315 }
308 316
309 return true; 317 return true;
310 } 318 }
311 319
312 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat ion) 320 void PannerNode::calculateAzimuthElevation(double* outAzimuth, double* outElevat ion)
313 { 321 {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 elevation = 180.0 - elevation; 372 elevation = 180.0 - elevation;
365 else if (elevation < -90.0) 373 else if (elevation < -90.0)
366 elevation = -180.0 - elevation; 374 elevation = -180.0 - elevation;
367 375
368 if (outAzimuth) 376 if (outAzimuth)
369 *outAzimuth = azimuth; 377 *outAzimuth = azimuth;
370 if (outElevation) 378 if (outElevation)
371 *outElevation = elevation; 379 *outElevation = elevation;
372 } 380 }
373 381
374
375 double PannerNode::calculateDopplerRate() 382 double PannerNode::calculateDopplerRate()
376 { 383 {
377 double dopplerShift = 1.0; 384 double dopplerShift = 1.0;
378 double dopplerFactor = listener()->dopplerFactor(); 385 double dopplerFactor = listener()->dopplerFactor();
379 386
380 if (dopplerFactor > 0.0) { 387 if (dopplerFactor > 0.0) {
381 double speedOfSound = listener()->speedOfSound(); 388 double speedOfSound = listener()->speedOfSound();
382 389
383 const FloatPoint3D &sourceVelocity = m_velocity; 390 const FloatPoint3D &sourceVelocity = m_velocity;
384 const FloatPoint3D &listenerVelocity = listener()->velocity(); 391 const FloatPoint3D &listenerVelocity = listener()->velocity();
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 436
430 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit ion); 437 double coneGain = m_coneEffect.gain(m_position, m_orientation, listenerPosit ion);
431 438
432 m_coneGain->setValue(static_cast<float>(coneGain)); 439 m_coneGain->setValue(static_cast<float>(coneGain));
433 440
434 return float(distanceGain * coneGain); 441 return float(distanceGain * coneGain);
435 } 442 }
436 443
437 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation) 444 void PannerNode::azimuthElevation(double* outAzimuth, double* outElevation)
438 { 445 {
446 ASSERT(context()->isAudioThread());
447
439 if (isAzimuthElevationDirty()) 448 if (isAzimuthElevationDirty())
440 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation); 449 calculateAzimuthElevation(&m_cachedAzimuth, &m_cachedElevation);
441 450
442 *outAzimuth = m_cachedAzimuth; 451 *outAzimuth = m_cachedAzimuth;
443 *outElevation = m_cachedElevation; 452 *outElevation = m_cachedElevation;
444 } 453 }
445 454
446 double PannerNode::dopplerRate() 455 double PannerNode::dopplerRate()
447 { 456 {
457 ASSERT(context()->isAudioThread());
Ken Russell (switch to Gerrit) 2014/03/19 00:37:41 Since dopplerRate() is public in PannerNode.h plea
KhNo 2014/03/19 01:46:42 Thanks for sharing I missed. I have added. :)
458
448 if (isDopplerRateDirty()) 459 if (isDopplerRateDirty())
449 m_cachedDopplerRate = calculateDopplerRate(); 460 m_cachedDopplerRate = calculateDopplerRate();
450 461
451 return m_cachedDopplerRate; 462 return m_cachedDopplerRate;
452 } 463 }
453 464
454 float PannerNode::distanceConeGain() 465 float PannerNode::distanceConeGain()
455 { 466 {
467 ASSERT(context()->isAudioThread());
468
456 if (isDistanceConeGainDirty()) 469 if (isDistanceConeGainDirty())
457 m_cachedDistanceConeGain = calculateDistanceConeGain(); 470 m_cachedDistanceConeGain = calculateDistanceConeGain();
458 471
459 return m_cachedDistanceConeGain; 472 return m_cachedDistanceConeGain;
460 } 473 }
461 474
462 bool PannerNode::isAzimuthElevationDirty() 475 bool PannerNode::isAzimuthElevationDirty()
463 { 476 {
464 // Do a quick test and return if possible. 477 // Do a quick test and return if possible.
465 if (m_cachedPosition != m_position) 478 if (m_cachedPosition != m_position)
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 visitedNodes.set(connectedNode, true); 540 visitedNodes.set(connectedNode, true);
528 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode s); // recurse 541 notifyAudioSourcesConnectedToNode(connectedNode, visitedNode s); // recurse
529 } 542 }
530 } 543 }
531 } 544 }
532 } 545 }
533 } 546 }
534 547
535 void PannerNode::updateCachedListener() 548 void PannerNode::updateCachedListener()
536 { 549 {
550 ASSERT(context()->isAudioThread());
551
537 m_cachedListener->setPosition(listener()->position()); 552 m_cachedListener->setPosition(listener()->position());
538 m_cachedListener->setOrientation(listener()->orientation()); 553 m_cachedListener->setOrientation(listener()->orientation());
539 m_cachedListener->setUpVector(listener()->upVector()); 554 m_cachedListener->setUpVector(listener()->upVector());
540 m_cachedListener->setVelocity(listener()->velocity()); 555 m_cachedListener->setVelocity(listener()->velocity());
541 m_cachedListener->setDopplerFactor(listener()->dopplerFactor()); 556 m_cachedListener->setDopplerFactor(listener()->dopplerFactor());
542 m_cachedListener->setSpeedOfSound(listener()->speedOfSound()); 557 m_cachedListener->setSpeedOfSound(listener()->speedOfSound());
543 } 558 }
544 559
545 void PannerNode::updateCachedSourceLocationInfo() 560 void PannerNode::updateCachedSourceLocationInfo()
546 { 561 {
562 ASSERT(context()->isAudioThread());
563
547 m_cachedPosition = m_position; 564 m_cachedPosition = m_position;
548 m_cachedOrientation = m_orientation; 565 m_cachedOrientation = m_orientation;
549 m_cachedVelocity = m_velocity; 566 m_cachedVelocity = m_velocity;
550 } 567 }
551 568
552 } // namespace WebCore 569 } // namespace WebCore
553 570
554 #endif // ENABLE(WEB_AUDIO) 571 #endif // ENABLE(WEB_AUDIO)
OLDNEW
« no previous file with comments | « Source/modules/webaudio/PannerNode.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698