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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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) |
KhNo
2014/03/13 09:45:11
Generally, default gain value should be 1.0f, Not
| |
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 Loading... | |
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 one of attributes which must be locked during process. | |
Raymond Toy
2014/03/13 21:37:46
This comment is not very helpful. Be more explicit
KhNo
2014/03/14 10:39:58
Done.
| |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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()); | |
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 Loading... | |
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) |
OLD | NEW |