Modified: trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp (278283 => 278284)
--- trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp 2021-05-31 21:14:52 UTC (rev 278283)
+++ trunk/Source/WebCore/Modules/webaudio/PannerNode.cpp 2021-06-01 00:03:03 UTC (rev 278284)
@@ -58,19 +58,19 @@
if (result.hasException())
return result.releaseException();
- result = panner->setMaxDistance(options.maxDistance);
+ result = panner->setMaxDistanceForBindings(options.maxDistance);
if (result.hasException())
return result.releaseException();
- result = panner->setRefDistance(options.refDistance);
+ result = panner->setRefDistanceForBindings(options.refDistance);
if (result.hasException())
return result.releaseException();
- result = panner->setRolloffFactor(options.rolloffFactor);
+ result = panner->setRolloffFactorForBindings(options.rolloffFactor);
if (result.hasException())
return result.releaseException();
- result = panner->setConeOuterGain(options.coneOuterGain);
+ result = panner->setConeOuterGainForBindings(options.coneOuterGain);
if (result.hasException())
return result.releaseException();
@@ -79,7 +79,10 @@
PannerNode::PannerNode(BaseAudioContext& context, const PannerOptions& options)
: AudioNode(context, NodeTypePanner)
+ // Load the HRTF database asynchronously so we don't block the _javascript_ thread while creating the HRTF database.
+ , m_hrtfDatabaseLoader(HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(context.sampleRate()))
, m_panningModel(options.panningModel)
+ , m_panner(Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader.ptr()))
, m_positionX(AudioParam::create(context, "positionX"_s, options.positionX, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
, m_positionY(AudioParam::create(context, "positionY"_s, options.positionY, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
, m_positionZ(AudioParam::create(context, "positionZ"_s, options.positionZ, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
@@ -86,12 +89,10 @@
, m_orientationX(AudioParam::create(context, "orientationX"_s, options.orientationX, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
, m_orientationY(AudioParam::create(context, "orientationY"_s, options.orientationY, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
, m_orientationZ(AudioParam::create(context, "orientationZ"_s, options.orientationZ, -FLT_MAX, FLT_MAX, AutomationRate::ARate))
- // Load the HRTF database asynchronously so we don't block the _javascript_ thread while creating the HRTF database.
- , m_hrtfDatabaseLoader(HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(context.sampleRate()))
{
- setDistanceModel(options.distanceModel);
- setConeInnerAngle(options.coneInnerAngle);
- setConeOuterAngle(options.coneOuterAngle);
+ setDistanceModelForBindings(options.distanceModel);
+ setConeInnerAngleForBindings(options.coneInnerAngle);
+ setConeOuterAngleForBindings(options.coneOuterAngle);
addInput();
addOutput(2);
@@ -108,7 +109,7 @@
{
AudioBus* destination = output(0)->bus();
- if (!isInitialized() || !input(0)->isConnected() || !m_panner.get()) {
+ if (!isInitialized() || !input(0)->isConnected()) {
destination->zero();
return;
}
@@ -119,8 +120,21 @@
return;
}
- // HRTFDatabase should be loaded before proceeding for offline audio context when panningModel() is "HRTF".
- if (panningModel() == PanningModelType::HRTF && !m_hrtfDatabaseLoader->isLoaded()) {
+ // The audio thread can't block on this lock, so we use tryLock() instead.
+ if (!m_processLock.tryLock()) {
+ // Too bad - tryLock() failed. We must be in the middle of changing the panner.
+ destination->zero();
+ return;
+ }
+ Locker locker { AdoptLock, m_processLock };
+
+ if (!m_panner) {
+ destination->zero();
+ return;
+ }
+
+ // HRTFDatabase should be loaded before proceeding for offline audio context when m_panningModel is "HRTF".
+ if (m_panningModel == PanningModelType::HRTF && !m_hrtfDatabaseLoader->isLoaded()) {
if (context().isOfflineContext())
m_hrtfDatabaseLoader->waitForLoaderThreadCompletion();
else {
@@ -129,14 +143,6 @@
}
}
- // The audio thread can't block on this lock, so we use tryLock() instead.
- if (!m_processLock.tryLock()) {
- // Too bad - tryLock() failed. We must be in the middle of changing the panner.
- destination->zero();
- return;
- }
- Locker locker { AdoptLock, m_processLock };
-
if ((hasSampleAccurateValues() || listener().hasSampleAccurateValues()) && (shouldUseARate() || listener().shouldUseARate())) {
processSampleAccurateValues(destination, source, framesToProcess);
return;
@@ -157,6 +163,11 @@
void PannerNode::processOnlyAudioParams(size_t framesToProcess)
{
+ ASSERT(context().isAudioThread());
+ if (!m_processLock.tryLock())
+ return;
+
+ Locker locker { AdoptLock, m_processLock };
float values[AudioUtilities::renderQuantumSize];
ASSERT(framesToProcess <= AudioUtilities::renderQuantumSize);
@@ -245,39 +256,19 @@
|| m_orientationZ->automationRate() == AutomationRate::ARate;
}
-void PannerNode::initialize()
-{
- if (isInitialized())
- return;
-
- m_panner = Panner::create(m_panningModel, sampleRate(), m_hrtfDatabaseLoader.get());
-
- AudioNode::initialize();
-}
-
-void PannerNode::uninitialize()
-{
- if (!isInitialized())
- return;
-
- m_panner = nullptr;
- AudioNode::uninitialize();
-}
-
AudioListener& PannerNode::listener()
{
return context().listener();
}
-void PannerNode::setPanningModel(PanningModelType model)
+void PannerNode::setPanningModelForBindings(PanningModelType model)
{
ASSERT(isMainThread());
- if (!m_panner.get() || model != m_panningModel) {
- // This synchronizes with process().
- Locker locker { m_processLock };
-
- m_panner = Panner::create(model, sampleRate(), m_hrtfDatabaseLoader.get());
+ // This synchronizes with process().
+ Locker locker { m_processLock };
+ if (!m_panner || model != m_panningModel) {
+ m_panner = Panner::create(model, sampleRate(), m_hrtfDatabaseLoader.ptr());
m_panningModel = model;
}
}
@@ -336,12 +327,13 @@
return { };
}
-DistanceModelType PannerNode::distanceModel() const
+DistanceModelType PannerNode::distanceModelForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS
{
- return const_cast<PannerNode*>(this)->m_distanceEffect.model();
+ ASSERT(isMainThread());
+ return m_distanceEffect.model();
}
-void PannerNode::setDistanceModel(DistanceModelType model)
+void PannerNode::setDistanceModelForBindings(DistanceModelType model)
{
ASSERT(isMainThread());
@@ -351,7 +343,7 @@
m_distanceEffect.setModel(model, true);
}
-ExceptionOr<void> PannerNode::setRefDistance(double refDistance)
+ExceptionOr<void> PannerNode::setRefDistanceForBindings(double refDistance)
{
ASSERT(isMainThread());
@@ -365,7 +357,7 @@
return { };
}
-ExceptionOr<void> PannerNode::setMaxDistance(double maxDistance)
+ExceptionOr<void> PannerNode::setMaxDistanceForBindings(double maxDistance)
{
ASSERT(isMainThread());
@@ -379,7 +371,7 @@
return { };
}
-ExceptionOr<void> PannerNode::setRolloffFactor(double rolloffFactor)
+ExceptionOr<void> PannerNode::setRolloffFactorForBindings(double rolloffFactor)
{
ASSERT(isMainThread());
@@ -393,7 +385,7 @@
return { };
}
-ExceptionOr<void> PannerNode::setConeOuterGain(double gain)
+ExceptionOr<void> PannerNode::setConeOuterGainForBindings(double gain)
{
ASSERT(isMainThread());
@@ -407,7 +399,7 @@
return { };
}
-void PannerNode::setConeOuterAngle(double angle)
+void PannerNode::setConeOuterAngleForBindings(double angle)
{
ASSERT(isMainThread());
@@ -417,7 +409,7 @@
m_coneEffect.setOuterAngle(angle);
}
-void PannerNode::setConeInnerAngle(double angle)
+void PannerNode::setConeInnerAngleForBindings(double angle)
{
ASSERT(isMainThread());
@@ -515,6 +507,9 @@
bool PannerNode::requiresTailProcessing() const
{
+ if (!m_processLock.tryLock())
+ return true;
+ Locker locker { AdoptLock, m_processLock };
// If there's no internal panner method set up yet, assume we require tail
// processing in case the HRTF panner is set later, which does require tail
// processing.
@@ -539,6 +534,22 @@
return calculateDistanceConeGain(position(), orientation(), listener().position());
}
+double PannerNode::tailTime() const
+{
+ if (!m_processLock.tryLock())
+ return std::numeric_limits<double>::infinity();
+ Locker locker { AdoptLock, m_processLock };
+ return m_panner ? m_panner->tailTime() : 0;
+}
+
+double PannerNode::latencyTime() const
+{
+ if (!m_processLock.tryLock())
+ return std::numeric_limits<double>::infinity();
+ Locker locker { AdoptLock, m_processLock };
+ return m_panner ? m_panner->latencyTime() : 0;
+}
+
} // namespace WebCore
#endif // ENABLE(WEB_AUDIO)
Modified: trunk/Source/WebCore/Modules/webaudio/PannerNode.h (278283 => 278284)
--- trunk/Source/WebCore/Modules/webaudio/PannerNode.h 2021-05-31 21:14:52 UTC (rev 278283)
+++ trunk/Source/WebCore/Modules/webaudio/PannerNode.h 2021-06-01 00:03:03 UTC (rev 278284)
@@ -61,94 +61,90 @@
// AudioNode
void process(size_t framesToProcess) override;
void processOnlyAudioParams(size_t framesToProcess) final;
- void initialize() override;
- void uninitialize() override;
// Listener
AudioListener& listener();
// Panning model
- PanningModelType panningModel() const { return m_panningModel; }
- void setPanningModel(PanningModelType);
+ PanningModelType panningModelForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_panningModel; }
+ void setPanningModelForBindings(PanningModelType);
// Position
- FloatPoint3D position() const;
ExceptionOr<void> setPosition(float x, float y, float z);
- AudioParam& positionX() { return m_positionX.get(); }
- AudioParam& positionY() { return m_positionY.get(); }
- AudioParam& positionZ() { return m_positionZ.get(); }
+ AudioParam& positionX() WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_positionX.get(); }
+ AudioParam& positionY() WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_positionY.get(); }
+ AudioParam& positionZ() WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_positionZ.get(); }
// Orientation
- FloatPoint3D orientation() const;
ExceptionOr<void> setOrientation(float x, float y, float z);
- AudioParam& orientationX() { return m_orientationX.get(); }
- AudioParam& orientationY() { return m_orientationY.get(); }
- AudioParam& orientationZ() { return m_orientationZ.get(); }
+ AudioParam& orientationX() WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_orientationX.get(); }
+ AudioParam& orientationY() WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_orientationY.get(); }
+ AudioParam& orientationZ() WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_orientationZ.get(); }
// Distance parameters
- DistanceModelType distanceModel() const;
- void setDistanceModel(DistanceModelType);
+ DistanceModelType distanceModelForBindings() const;
+ void setDistanceModelForBindings(DistanceModelType);
- double refDistance() const { return m_distanceEffect.refDistance(); }
- ExceptionOr<void> setRefDistance(double);
+ double refDistanceForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_distanceEffect.refDistance(); }
+ ExceptionOr<void> setRefDistanceForBindings(double);
- double maxDistance() const { return m_distanceEffect.maxDistance(); }
- ExceptionOr<void> setMaxDistance(double);
+ double maxDistanceForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_distanceEffect.maxDistance(); }
+ ExceptionOr<void> setMaxDistanceForBindings(double);
- double rolloffFactor() const { return m_distanceEffect.rolloffFactor(); }
- ExceptionOr<void> setRolloffFactor(double);
+ double rolloffFactorForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_distanceEffect.rolloffFactor(); }
+ ExceptionOr<void> setRolloffFactorForBindings(double);
// Sound cones - angles in degrees
- double coneInnerAngle() const { return m_coneEffect.innerAngle(); }
- void setConeInnerAngle(double);
+ double coneInnerAngleForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_coneEffect.innerAngle(); }
+ void setConeInnerAngleForBindings(double);
- double coneOuterAngle() const { return m_coneEffect.outerAngle(); }
- void setConeOuterAngle(double);
+ double coneOuterAngleForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_coneEffect.outerAngle(); }
+ void setConeOuterAngleForBindings(double);
- double coneOuterGain() const { return m_coneEffect.outerGain(); }
- ExceptionOr<void> setConeOuterGain(double);
+ double coneOuterGainForBindings() const WTF_IGNORES_THREAD_SAFETY_ANALYSIS { ASSERT(isMainThread()); return m_coneEffect.outerGain(); }
+ ExceptionOr<void> setConeOuterGainForBindings(double);
ExceptionOr<void> setChannelCount(unsigned) final;
ExceptionOr<void> setChannelCountMode(ChannelCountMode) final;
- void azimuthElevation(double* outAzimuth, double* outElevation);
+ double tailTime() const final;
+ double latencyTime() const final;
- double tailTime() const override { return m_panner ? m_panner->tailTime() : 0; }
- double latencyTime() const override { return m_panner ? m_panner->latencyTime() : 0; }
-
private:
PannerNode(BaseAudioContext&, const PannerOptions&);
- void calculateAzimuthElevation(double* outAzimuth, double* outElevation, const FloatPoint3D& position, const FloatPoint3D& listenerPosition, const FloatPoint3D& listenerForward, const FloatPoint3D& listenerUp);
- float calculateDistanceConeGain(const FloatPoint3D& position, const FloatPoint3D& orientation, const FloatPoint3D& listenerPosition);
+ void calculateAzimuthElevation(double* outAzimuth, double* outElevation, const FloatPoint3D& position, const FloatPoint3D& listenerPosition, const FloatPoint3D& listenerForward, const FloatPoint3D& listenerUp) WTF_REQUIRES_LOCK(m_processLock);
+ float calculateDistanceConeGain(const FloatPoint3D& position, const FloatPoint3D& orientation, const FloatPoint3D& listenerPosition) WTF_REQUIRES_LOCK(m_processLock);
// Returns the combined distance and cone gain attenuation.
- float distanceConeGain();
+ float distanceConeGain() WTF_REQUIRES_LOCK(m_processLock);
bool requiresTailProcessing() const final;
- void processSampleAccurateValues(AudioBus* destination, const AudioBus* source, size_t framesToProcess);
- bool hasSampleAccurateValues() const;
- bool shouldUseARate() const;
+ void azimuthElevation(double* outAzimuth, double* outElevation) WTF_REQUIRES_LOCK(m_processLock);
+ void processSampleAccurateValues(AudioBus* destination, const AudioBus* source, size_t framesToProcess) WTF_REQUIRES_LOCK(m_processLock);
+ bool hasSampleAccurateValues() const WTF_REQUIRES_LOCK(m_processLock);
+ bool shouldUseARate() const WTF_REQUIRES_LOCK(m_processLock);
- std::unique_ptr<Panner> m_panner;
- PanningModelType m_panningModel;
+ FloatPoint3D position() const WTF_REQUIRES_LOCK(m_processLock);
+ FloatPoint3D orientation() const WTF_REQUIRES_LOCK(m_processLock);
+ Ref<HRTFDatabaseLoader> m_hrtfDatabaseLoader;
+ PanningModelType m_panningModel WTF_GUARDED_BY_LOCK(m_processLock);
+ std::unique_ptr<Panner> m_panner WTF_GUARDED_BY_LOCK(m_processLock);
+
// Gain
- DistanceEffect m_distanceEffect;
- ConeEffect m_coneEffect;
+ DistanceEffect m_distanceEffect WTF_GUARDED_BY_LOCK(m_processLock);
+ ConeEffect m_coneEffect WTF_GUARDED_BY_LOCK(m_processLock);
- Ref<AudioParam> m_positionX;
- Ref<AudioParam> m_positionY;
- Ref<AudioParam> m_positionZ;
+ Ref<AudioParam> m_positionX WTF_GUARDED_BY_LOCK(m_processLock);
+ Ref<AudioParam> m_positionY WTF_GUARDED_BY_LOCK(m_processLock);
+ Ref<AudioParam> m_positionZ WTF_GUARDED_BY_LOCK(m_processLock);
- Ref<AudioParam> m_orientationX;
- Ref<AudioParam> m_orientationY;
- Ref<AudioParam> m_orientationZ;
+ Ref<AudioParam> m_orientationX WTF_GUARDED_BY_LOCK(m_processLock);
+ Ref<AudioParam> m_orientationY WTF_GUARDED_BY_LOCK(m_processLock);
+ Ref<AudioParam> m_orientationZ WTF_GUARDED_BY_LOCK(m_processLock);
- // HRTF Database loader
- RefPtr<HRTFDatabaseLoader> m_hrtfDatabaseLoader;
-
// Synchronize process() with setting of the panning model, source's location
// information, listener, distance parameters and sound cones.
mutable Lock m_processLock;