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

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