Chromium Code Reviews| 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 |