зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 4 changesets (bug 1476744, bug 1148354) for failing android at http://10.0.2.2:8854/tests/dom/media/test/crashtests/doppler-1.html on a CLOSED TREE
Backed out changeset 0ae34db4c34f (bug 1476744) Backed out changeset 97d89ba5f93d (bug 1148354) Backed out changeset d9174c023701 (bug 1148354) Backed out changeset b4085dba45c5 (bug 1148354)
This commit is contained in:
Родитель
fced036309
Коммит
98338c6ff5
|
@ -669,6 +669,9 @@ AudioBufferSourceNode::DestroyMediaStream()
|
|||
mStream->RemoveMainThreadListener(this);
|
||||
}
|
||||
AudioNode::DestroyMediaStream();
|
||||
if (hadStream && Context()) {
|
||||
Context()->UnregisterAudioBufferSourceNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
@ -93,6 +93,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioContext)
|
|||
}
|
||||
// mDecodeJobs owns the WebAudioDecodeJob objects whose lifetime is managed explicitly.
|
||||
// mAllNodes is an array of weak pointers, ignore it here.
|
||||
// mPannerNodes is an array of weak pointers, ignore it here.
|
||||
// mBasicWaveFormCache cannot participate in cycles, ignore it here.
|
||||
|
||||
// Remove weak reference on the global window as the context is not usable
|
||||
|
@ -113,6 +114,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AudioContext,
|
|||
}
|
||||
// mDecodeJobs owns the WebAudioDecodeJob objects whose lifetime is managed explicitly.
|
||||
// mAllNodes is an array of weak pointers, ignore it here.
|
||||
// mPannerNodes is an array of weak pointers, ignore it here.
|
||||
// mBasicWaveFormCache cannot participate in cycles, ignore it here.
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
@ -653,6 +655,29 @@ AudioContext::UnregisterActiveNode(AudioNode* aNode)
|
|||
mActiveNodes.RemoveEntry(aNode);
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode)
|
||||
{
|
||||
UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::UnregisterPannerNode(PannerNode* aNode)
|
||||
{
|
||||
mPannerNodes.RemoveEntry(aNode);
|
||||
if (mListener) {
|
||||
mListener->UnregisterPannerNode(aNode);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::UpdatePannerSource()
|
||||
{
|
||||
for (auto iter = mPannerNodes.Iter(); !iter.Done(); iter.Next()) {
|
||||
iter.Get()->GetKey()->FindConnectedSources();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
AudioContext::MaxChannelCount() const
|
||||
{
|
||||
|
@ -1177,6 +1202,7 @@ AudioContext::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
|||
amount += mDecodeJobs[i]->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
amount += mActiveNodes.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mPannerNodes.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
|
|
@ -309,6 +309,10 @@ public:
|
|||
// unregistering would not be safe.
|
||||
void UnregisterActiveNode(AudioNode* aNode);
|
||||
|
||||
void UnregisterAudioBufferSourceNode(AudioBufferSourceNode* aNode);
|
||||
void UnregisterPannerNode(PannerNode* aNode);
|
||||
void UpdatePannerSource();
|
||||
|
||||
uint32_t MaxChannelCount() const;
|
||||
|
||||
uint32_t ActiveNodeCount() const;
|
||||
|
@ -367,6 +371,9 @@ private:
|
|||
nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
|
||||
// Raw (non-owning) references to all AudioNodes for this AudioContext.
|
||||
nsTHashtable<nsPtrHashKey<AudioNode> > mAllNodes;
|
||||
// Hashsets containing all the PannerNodes, to compute the doppler shift.
|
||||
// These are weak pointers.
|
||||
nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
|
||||
// Cache to avoid recomputing basic waveforms all the time.
|
||||
RefPtr<BasicWaveFormCache> mBasicWaveFormCache;
|
||||
// Number of channels passed in the OfflineAudioContext ctor.
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "AudioListener.h"
|
||||
#include "AudioContext.h"
|
||||
#include "mozilla/dom/AudioListenerBinding.h"
|
||||
#include "MediaStreamGraphImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -17,55 +16,14 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AudioListener, mContext)
|
|||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioListener, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioListener, Release)
|
||||
|
||||
AudioListenerEngine::AudioListenerEngine()
|
||||
: mPosition()
|
||||
, mFrontVector(0., 0., -1.)
|
||||
, mRightVector(1., 0., 0.)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AudioListenerEngine::RecvListenerEngineEvent(
|
||||
AudioListenerEngine::AudioListenerParameter aParameter,
|
||||
const ThreeDPoint& aValue)
|
||||
{
|
||||
switch (aParameter) {
|
||||
case AudioListenerParameter::POSITION:
|
||||
mPosition = aValue;
|
||||
break;
|
||||
case AudioListenerParameter::FRONT:
|
||||
mFrontVector = aValue;
|
||||
break;
|
||||
case AudioListenerParameter::RIGHT:
|
||||
mRightVector = aValue;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Not handled");
|
||||
}
|
||||
}
|
||||
|
||||
const ThreeDPoint&
|
||||
AudioListenerEngine::Position() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
const ThreeDPoint&
|
||||
AudioListenerEngine::FrontVector() const
|
||||
{
|
||||
return mFrontVector;
|
||||
}
|
||||
const ThreeDPoint&
|
||||
AudioListenerEngine::RightVector() const
|
||||
{
|
||||
return mRightVector;
|
||||
}
|
||||
|
||||
AudioListener::AudioListener(AudioContext* aContext)
|
||||
: mContext(aContext)
|
||||
, mEngine(MakeUnique<AudioListenerEngine>())
|
||||
, mPosition()
|
||||
, mFrontVector(0., 0., -1.)
|
||||
, mRightVector(1., 0., 0.)
|
||||
, mVelocity()
|
||||
, mDopplerFactor(1.)
|
||||
, mSpeedOfSound(343.3) // meters/second
|
||||
{
|
||||
MOZ_ASSERT(aContext);
|
||||
}
|
||||
|
@ -102,65 +60,70 @@ AudioListener::SetOrientation(double aX, double aY, double aZ,
|
|||
|
||||
if (!mFrontVector.FuzzyEqual(front)) {
|
||||
mFrontVector = front;
|
||||
SendListenerEngineEvent(AudioListenerEngine::AudioListenerParameter::FRONT,
|
||||
mFrontVector);
|
||||
SendThreeDPointParameterToStream(PannerNode::LISTENER_FRONT_VECTOR, front);
|
||||
}
|
||||
if (!mRightVector.FuzzyEqual(right)) {
|
||||
mRightVector = right;
|
||||
SendListenerEngineEvent(AudioListenerEngine::AudioListenerParameter::RIGHT,
|
||||
mRightVector);
|
||||
SendThreeDPointParameterToStream(PannerNode::LISTENER_RIGHT_VECTOR, right);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioListener::SetPosition(double aX, double aY, double aZ)
|
||||
AudioListener::RegisterPannerNode(PannerNode* aPannerNode)
|
||||
{
|
||||
if (WebAudioUtils::FuzzyEqual(mPosition.x, aX) &&
|
||||
WebAudioUtils::FuzzyEqual(mPosition.y, aY) &&
|
||||
WebAudioUtils::FuzzyEqual(mPosition.z, aZ)) {
|
||||
return;
|
||||
}
|
||||
mPosition.x = aX;
|
||||
mPosition.y = aY;
|
||||
mPosition.z = aZ;
|
||||
SendListenerEngineEvent(AudioListenerEngine::AudioListenerParameter::POSITION,
|
||||
mPosition);
|
||||
mPanners.AppendElement(aPannerNode);
|
||||
|
||||
// Let the panner node know about our parameters
|
||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_POSITION, mPosition);
|
||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_FRONT_VECTOR, mFrontVector);
|
||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_RIGHT_VECTOR, mRightVector);
|
||||
aPannerNode->SendThreeDPointParameterToStream(PannerNode::LISTENER_VELOCITY, mVelocity);
|
||||
aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_DOPPLER_FACTOR, mDopplerFactor);
|
||||
aPannerNode->SendDoubleParameterToStream(PannerNode::LISTENER_SPEED_OF_SOUND, mSpeedOfSound);
|
||||
UpdatePannersVelocity();
|
||||
}
|
||||
|
||||
void AudioListener::UnregisterPannerNode(PannerNode* aPannerNode)
|
||||
{
|
||||
mPanners.RemoveElement(aPannerNode);
|
||||
}
|
||||
|
||||
void
|
||||
AudioListener::SendListenerEngineEvent(
|
||||
AudioListenerEngine::AudioListenerParameter aParameter,
|
||||
const ThreeDPoint& aValue)
|
||||
AudioListener::SendDoubleParameterToStream(uint32_t aIndex, double aValue)
|
||||
{
|
||||
class Message final : public ControlMessage
|
||||
{
|
||||
public:
|
||||
Message(AudioListenerEngine* aEngine,
|
||||
AudioListenerEngine::AudioListenerParameter aParameter,
|
||||
const ThreeDPoint& aValue)
|
||||
: ControlMessage(nullptr)
|
||||
, mEngine(aEngine)
|
||||
, mParameter(aParameter)
|
||||
, mValue(aValue)
|
||||
{
|
||||
for (uint32_t i = 0; i < mPanners.Length(); ++i) {
|
||||
if (mPanners[i]) {
|
||||
mPanners[i]->SendDoubleParameterToStream(aIndex, aValue);
|
||||
}
|
||||
void Run() override
|
||||
{
|
||||
mEngine->RecvListenerEngineEvent(mParameter, mValue);
|
||||
}
|
||||
AudioListenerEngine* mEngine;
|
||||
AudioListenerEngine::AudioListenerParameter mParameter;
|
||||
ThreeDPoint mValue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
mContext->DestinationStream()->GraphImpl()->AppendMessage(
|
||||
MakeUnique<Message>(mEngine.get(), aParameter, aValue));
|
||||
void
|
||||
AudioListener::SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue)
|
||||
{
|
||||
for (uint32_t i = 0; i < mPanners.Length(); ++i) {
|
||||
if (mPanners[i]) {
|
||||
mPanners[i]->SendThreeDPointParameterToStream(aIndex, aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioListener::UpdatePannersVelocity()
|
||||
{
|
||||
for (uint32_t i = 0; i < mPanners.Length(); ++i) {
|
||||
if (mPanners[i]) {
|
||||
mPanners[i]->SendDopplerToSourcesIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
AudioListener::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return aMallocSizeOf(this);
|
||||
size_t amount = aMallocSizeOf(this);
|
||||
// AudioNodes are tracked separately
|
||||
amount += mPanners.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -21,29 +21,6 @@ namespace mozilla {
|
|||
|
||||
namespace dom {
|
||||
|
||||
class AudioListenerEngine final
|
||||
{
|
||||
public:
|
||||
enum class AudioListenerParameter
|
||||
{
|
||||
POSITION,
|
||||
FRONT, // unit length
|
||||
RIGHT // unit length, orthogonal to FRONT
|
||||
};
|
||||
AudioListenerEngine();
|
||||
void RecvListenerEngineEvent(
|
||||
AudioListenerEngine::AudioListenerParameter aParameter,
|
||||
const ThreeDPoint& aValue);
|
||||
const ThreeDPoint& Position() const;
|
||||
const ThreeDPoint& FrontVector() const;
|
||||
const ThreeDPoint& RightVector() const;
|
||||
|
||||
private:
|
||||
ThreeDPoint mPosition;
|
||||
ThreeDPoint mFrontVector;
|
||||
ThreeDPoint mRightVector;
|
||||
};
|
||||
|
||||
class AudioListener final : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
|
@ -61,26 +38,92 @@ public:
|
|||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void SetPosition(double aX, double aY, double aZ);
|
||||
double DopplerFactor() const
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
void SetDopplerFactor(double aDopplerFactor)
|
||||
{
|
||||
if (WebAudioUtils::FuzzyEqual(mDopplerFactor, aDopplerFactor)) {
|
||||
return;
|
||||
}
|
||||
mDopplerFactor = aDopplerFactor;
|
||||
SendDoubleParameterToStream(PannerNode::LISTENER_DOPPLER_FACTOR, mDopplerFactor);
|
||||
}
|
||||
|
||||
double SpeedOfSound() const
|
||||
{
|
||||
return mSpeedOfSound;
|
||||
}
|
||||
void SetSpeedOfSound(double aSpeedOfSound)
|
||||
{
|
||||
if (WebAudioUtils::FuzzyEqual(mSpeedOfSound, aSpeedOfSound)) {
|
||||
return;
|
||||
}
|
||||
mSpeedOfSound = aSpeedOfSound;
|
||||
SendDoubleParameterToStream(PannerNode::LISTENER_SPEED_OF_SOUND, mSpeedOfSound);
|
||||
}
|
||||
|
||||
void SetPosition(double aX, double aY, double aZ)
|
||||
{
|
||||
if (WebAudioUtils::FuzzyEqual(mPosition.x, aX) &&
|
||||
WebAudioUtils::FuzzyEqual(mPosition.y, aY) &&
|
||||
WebAudioUtils::FuzzyEqual(mPosition.z, aZ)) {
|
||||
return;
|
||||
}
|
||||
mPosition.x = aX;
|
||||
mPosition.y = aY;
|
||||
mPosition.z = aZ;
|
||||
SendThreeDPointParameterToStream(PannerNode::LISTENER_POSITION, mPosition);
|
||||
}
|
||||
|
||||
const ThreeDPoint& Position() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
void SetOrientation(double aX, double aY, double aZ,
|
||||
double aXUp, double aYUp, double aZUp);
|
||||
|
||||
const AudioListenerEngine* Engine() { return mEngine.get(); }
|
||||
const ThreeDPoint& Velocity() const
|
||||
{
|
||||
return mVelocity;
|
||||
}
|
||||
|
||||
void SetVelocity(double aX, double aY, double aZ)
|
||||
{
|
||||
if (WebAudioUtils::FuzzyEqual(mVelocity.x, aX) &&
|
||||
WebAudioUtils::FuzzyEqual(mVelocity.y, aY) &&
|
||||
WebAudioUtils::FuzzyEqual(mVelocity.z, aZ)) {
|
||||
return;
|
||||
}
|
||||
mVelocity.x = aX;
|
||||
mVelocity.y = aY;
|
||||
mVelocity.z = aZ;
|
||||
SendThreeDPointParameterToStream(PannerNode::LISTENER_VELOCITY, mVelocity);
|
||||
UpdatePannersVelocity();
|
||||
}
|
||||
|
||||
void RegisterPannerNode(PannerNode* aPannerNode);
|
||||
void UnregisterPannerNode(PannerNode* aPannerNode);
|
||||
|
||||
private:
|
||||
void SendListenerEngineEvent(
|
||||
AudioListenerEngine::AudioListenerParameter aParameter,
|
||||
const ThreeDPoint& aValue);
|
||||
|
||||
~AudioListener() = default;
|
||||
~AudioListener() {}
|
||||
|
||||
void SendDoubleParameterToStream(uint32_t aIndex, double aValue);
|
||||
void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue);
|
||||
void UpdatePannersVelocity();
|
||||
|
||||
private:
|
||||
friend class PannerNode;
|
||||
RefPtr<AudioContext> mContext;
|
||||
const UniquePtr<AudioListenerEngine> mEngine;
|
||||
ThreeDPoint mPosition;
|
||||
ThreeDPoint mFrontVector;
|
||||
ThreeDPoint mRightVector;
|
||||
ThreeDPoint mVelocity;
|
||||
double mDopplerFactor;
|
||||
double mSpeedOfSound;
|
||||
nsTArray<WeakPtr<PannerNode> > mPanners;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -244,6 +244,9 @@ AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
|
|||
}
|
||||
aDestination.NotifyInputsChanged();
|
||||
|
||||
// This connection may have connected a panner and a source.
|
||||
Context()->UpdatePannerSource();
|
||||
|
||||
return &aDestination;
|
||||
}
|
||||
|
||||
|
@ -451,6 +454,9 @@ AudioNode::Disconnect(ErrorResult& aRv)
|
|||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// This disconnection may have disconnected a panner and a source.
|
||||
Context()->UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -478,6 +484,9 @@ AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
|
|||
return aInputNode.mOutputPort == aOutput;
|
||||
});
|
||||
}
|
||||
|
||||
// This disconnection may have disconnected a panner and a source.
|
||||
Context()->UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -501,6 +510,9 @@ AudioNode::Disconnect(AudioNode& aDestination, ErrorResult& aRv)
|
|||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// This disconnection may have disconnected a panner and a source.
|
||||
Context()->UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -532,6 +544,9 @@ AudioNode::Disconnect(AudioNode& aDestination,
|
|||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// This disconnection may have disconnected a panner and a source.
|
||||
Context()->UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -570,6 +585,9 @@ AudioNode::Disconnect(AudioNode& aDestination,
|
|||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// This disconnection may have disconnected a panner and a source.
|
||||
Context()->UpdatePannerSource();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -27,6 +27,9 @@ using namespace std;
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(PannerNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PannerNode, AudioNode)
|
||||
if (tmp->Context()) {
|
||||
tmp->Context()->UnregisterPannerNode(tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPositionX, mPositionY, mPositionZ, mOrientationX, mOrientationY, mOrientationZ)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PannerNode, AudioNode)
|
||||
|
@ -42,14 +45,10 @@ NS_IMPL_RELEASE_INHERITED(PannerNode, AudioNode)
|
|||
class PannerNodeEngine final : public AudioNodeEngine
|
||||
{
|
||||
public:
|
||||
explicit PannerNodeEngine(AudioNode* aNode,
|
||||
AudioDestinationNode* aDestination,
|
||||
const AudioListenerEngine* aListenerEngine)
|
||||
explicit PannerNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mDestination(aDestination->Stream())
|
||||
, mListenerEngine(aListenerEngine)
|
||||
// Please keep these default values consistent with PannerNode::PannerNode
|
||||
// below.
|
||||
// Please keep these default values consistent with PannerNode::PannerNode below.
|
||||
, mPanningModelFunction(&PannerNodeEngine::EqualPowerPanningFunction)
|
||||
, mDistanceModelFunction(&PannerNodeEngine::InverseGainFunction)
|
||||
, mPositionX(0.)
|
||||
|
@ -58,12 +57,17 @@ public:
|
|||
, mOrientationX(1.)
|
||||
, mOrientationY(0.)
|
||||
, mOrientationZ(0.)
|
||||
, mVelocity()
|
||||
, mRefDistance(1.)
|
||||
, mMaxDistance(10000.)
|
||||
, mRolloffFactor(1.)
|
||||
, mConeInnerAngle(360.)
|
||||
, mConeOuterAngle(360.)
|
||||
, mConeOuterGain(0.)
|
||||
// These will be initialized when a PannerNode is created, so just initialize them
|
||||
// to some dummy values here.
|
||||
, mListenerDopplerFactor(0.)
|
||||
, mListenerSpeedOfSound(0.)
|
||||
, mLeftOverData(INT_MIN)
|
||||
{
|
||||
}
|
||||
|
@ -148,6 +152,10 @@ public:
|
|||
void SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aParam) override
|
||||
{
|
||||
switch (aIndex) {
|
||||
case PannerNode::LISTENER_POSITION: mListenerPosition = aParam; break;
|
||||
case PannerNode::LISTENER_FRONT_VECTOR: mListenerFrontVector = aParam; break;
|
||||
case PannerNode::LISTENER_RIGHT_VECTOR: mListenerRightVector = aParam; break;
|
||||
case PannerNode::LISTENER_VELOCITY: mListenerVelocity = aParam; break;
|
||||
case PannerNode::POSITION:
|
||||
mPositionX.SetValue(aParam.x);
|
||||
mPositionY.SetValue(aParam.y);
|
||||
|
@ -158,6 +166,7 @@ public:
|
|||
mOrientationY.SetValue(aParam.y);
|
||||
mOrientationZ.SetValue(aParam.z);
|
||||
break;
|
||||
case PannerNode::VELOCITY: mVelocity = aParam; break;
|
||||
default:
|
||||
NS_ERROR("Bad PannerNodeEngine ThreeDPointParameter");
|
||||
}
|
||||
|
@ -165,6 +174,8 @@ public:
|
|||
void SetDoubleParameter(uint32_t aIndex, double aParam) override
|
||||
{
|
||||
switch (aIndex) {
|
||||
case PannerNode::LISTENER_DOPPLER_FACTOR: mListenerDopplerFactor = aParam; break;
|
||||
case PannerNode::LISTENER_SPEED_OF_SOUND: mListenerSpeedOfSound = aParam; break;
|
||||
case PannerNode::REF_DISTANCE: mRefDistance = aParam; break;
|
||||
case PannerNode::MAX_DISTANCE: mMaxDistance = aParam; break;
|
||||
case PannerNode::ROLLOFF_FACTOR: mRolloffFactor = aParam; break;
|
||||
|
@ -256,9 +267,6 @@ public:
|
|||
// thread untile mPanningModelFunction has changed, and this happens strictly
|
||||
// later, via a MediaStreamGraph ControlMessage.
|
||||
nsAutoPtr<HRTFPanner> mHRTFPanner;
|
||||
// This is set in the ctor, and guaranteed to live longer than this engine:
|
||||
// its lifetime is the same as the AudioContext itself.
|
||||
const AudioListenerEngine* mListenerEngine;
|
||||
typedef void (PannerNodeEngine::*PanningModelFunction)(const AudioBlock& aInput, AudioBlock* aOutput, StreamTime tick);
|
||||
PanningModelFunction mPanningModelFunction;
|
||||
typedef float (PannerNodeEngine::*DistanceModelFunction)(double aDistance);
|
||||
|
@ -269,12 +277,19 @@ public:
|
|||
AudioParamTimeline mOrientationX;
|
||||
AudioParamTimeline mOrientationY;
|
||||
AudioParamTimeline mOrientationZ;
|
||||
ThreeDPoint mVelocity;
|
||||
double mRefDistance;
|
||||
double mMaxDistance;
|
||||
double mRolloffFactor;
|
||||
double mConeInnerAngle;
|
||||
double mConeOuterAngle;
|
||||
double mConeOuterGain;
|
||||
ThreeDPoint mListenerPosition;
|
||||
ThreeDPoint mListenerFrontVector;
|
||||
ThreeDPoint mListenerRightVector;
|
||||
ThreeDPoint mListenerVelocity;
|
||||
double mListenerDopplerFactor;
|
||||
double mListenerSpeedOfSound;
|
||||
int mLeftOverData;
|
||||
};
|
||||
|
||||
|
@ -292,6 +307,7 @@ PannerNode::PannerNode(AudioContext* aContext)
|
|||
, mOrientationX(new AudioParam(this, PannerNode::ORIENTATIONX, this->NodeType(), 1.0f))
|
||||
, mOrientationY(new AudioParam(this, PannerNode::ORIENTATIONY, this->NodeType(), 0.f))
|
||||
, mOrientationZ(new AudioParam(this, PannerNode::ORIENTATIONZ, this->NodeType(), 0.f))
|
||||
, mVelocity()
|
||||
, mRefDistance(1.)
|
||||
, mMaxDistance(10000.)
|
||||
, mRolloffFactor(1.)
|
||||
|
@ -299,12 +315,19 @@ PannerNode::PannerNode(AudioContext* aContext)
|
|||
, mConeOuterAngle(360.)
|
||||
, mConeOuterGain(0.)
|
||||
{
|
||||
mStream = AudioNodeStream::Create(
|
||||
aContext,
|
||||
new PannerNodeEngine(
|
||||
this, aContext->Destination(), aContext->Listener()->Engine()),
|
||||
AudioNodeStream::NO_STREAM_FLAGS,
|
||||
aContext->Graph());
|
||||
mStream = AudioNodeStream::Create(aContext,
|
||||
new PannerNodeEngine(this, aContext->Destination()),
|
||||
AudioNodeStream::NO_STREAM_FLAGS,
|
||||
aContext->Graph());
|
||||
// We should register once we have set up our stream and engine.
|
||||
Context()->Listener()->RegisterPannerNode(this);
|
||||
}
|
||||
|
||||
PannerNode::~PannerNode()
|
||||
{
|
||||
if (Context()) {
|
||||
Context()->UnregisterPannerNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<PannerNode>
|
||||
|
@ -354,7 +377,9 @@ void PannerNode::SetPanningModel(PanningModelType aPanningModel)
|
|||
size_t
|
||||
PannerNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return AudioNode::SizeOfExcludingThis(aMallocSizeOf);
|
||||
size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mSources.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -369,6 +394,14 @@ PannerNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return PannerNode_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void PannerNode::DestroyMediaStream()
|
||||
{
|
||||
if (Context()) {
|
||||
Context()->UnregisterPannerNode(this);
|
||||
}
|
||||
AudioNode::DestroyMediaStream();
|
||||
}
|
||||
|
||||
// Those three functions are described in the spec.
|
||||
float
|
||||
PannerNodeEngine::LinearGainFunction(double aDistance)
|
||||
|
@ -446,8 +479,10 @@ PannerNodeEngine::EqualPowerPanningFunction(const AudioBlock& aInput,
|
|||
|
||||
// For a stereo source, when both the listener and the panner are in
|
||||
// the same spot, and no cone gain is specified, this node is noop.
|
||||
if (inputChannels == 2 && mListenerEngine->Position() == position &&
|
||||
mConeInnerAngle == 360 && mConeOuterAngle == 360) {
|
||||
if (inputChannels == 2 &&
|
||||
mListenerPosition == position &&
|
||||
mConeInnerAngle == 360 &&
|
||||
mConeOuterAngle == 360) {
|
||||
*aOutput = aInput;
|
||||
return;
|
||||
}
|
||||
|
@ -606,7 +641,7 @@ PannerNodeEngine::EqualPowerPanningFunction(const AudioBlock& aInput,
|
|||
void
|
||||
PannerNodeEngine::ComputeAzimuthAndElevation(const ThreeDPoint& position, float& aAzimuth, float& aElevation)
|
||||
{
|
||||
ThreeDPoint sourceListener = position - mListenerEngine->Position();
|
||||
ThreeDPoint sourceListener = position - mListenerPosition;
|
||||
if (sourceListener.IsZero()) {
|
||||
aAzimuth = 0.0;
|
||||
aElevation = 0.0;
|
||||
|
@ -616,8 +651,8 @@ PannerNodeEngine::ComputeAzimuthAndElevation(const ThreeDPoint& position, float&
|
|||
sourceListener.Normalize();
|
||||
|
||||
// Project the source-listener vector on the x-z plane.
|
||||
const ThreeDPoint& listenerFront = mListenerEngine->FrontVector();
|
||||
const ThreeDPoint& listenerRight = mListenerEngine->RightVector();
|
||||
const ThreeDPoint& listenerFront = mListenerFrontVector;
|
||||
const ThreeDPoint& listenerRight = mListenerRightVector;
|
||||
ThreeDPoint up = listenerRight.CrossProduct(listenerFront);
|
||||
|
||||
double upProjection = sourceListener.DotProduct(up);
|
||||
|
@ -666,7 +701,7 @@ PannerNodeEngine::ComputeConeGain(const ThreeDPoint& position,
|
|||
}
|
||||
|
||||
// Normalized source-listener vector
|
||||
ThreeDPoint sourceToListener = mListenerEngine->Position() - position;
|
||||
ThreeDPoint sourceToListener = mListenerPosition - position;
|
||||
sourceToListener.Normalize();
|
||||
|
||||
// Angle between the source orientation vector and the source-listener vector
|
||||
|
@ -698,10 +733,98 @@ PannerNodeEngine::ComputeConeGain(const ThreeDPoint& position,
|
|||
double
|
||||
PannerNodeEngine::ComputeDistanceGain(const ThreeDPoint& position)
|
||||
{
|
||||
ThreeDPoint distanceVec = position - mListenerEngine->Position();
|
||||
ThreeDPoint distanceVec = position - mListenerPosition;
|
||||
float distance = sqrt(distanceVec.DotProduct(distanceVec));
|
||||
return std::max(0.0f, (this->*mDistanceModelFunction)(distance));
|
||||
}
|
||||
|
||||
float
|
||||
PannerNode::ComputeDopplerShift()
|
||||
{
|
||||
double dopplerShift = 1.0; // Initialize to default value
|
||||
|
||||
AudioListener* listener = Context()->Listener();
|
||||
|
||||
if (listener->DopplerFactor() > 0) {
|
||||
// Don't bother if both source and listener have no velocity.
|
||||
if (!mVelocity.IsZero() || !listener->Velocity().IsZero()) {
|
||||
// Calculate the source to listener vector.
|
||||
ThreeDPoint sourceToListener = ConvertAudioParamTo3DP(mPositionX, mPositionY, mPositionZ) - listener->Velocity();
|
||||
|
||||
double sourceListenerMagnitude = sourceToListener.Magnitude();
|
||||
|
||||
double listenerProjection = sourceToListener.DotProduct(listener->Velocity()) / sourceListenerMagnitude;
|
||||
double sourceProjection = sourceToListener.DotProduct(mVelocity) / sourceListenerMagnitude;
|
||||
|
||||
listenerProjection = -listenerProjection;
|
||||
sourceProjection = -sourceProjection;
|
||||
|
||||
double scaledSpeedOfSound = listener->SpeedOfSound() / listener->DopplerFactor();
|
||||
listenerProjection = min(listenerProjection, scaledSpeedOfSound);
|
||||
sourceProjection = min(sourceProjection, scaledSpeedOfSound);
|
||||
|
||||
dopplerShift = ((listener->SpeedOfSound() - listener->DopplerFactor() * listenerProjection) / (listener->SpeedOfSound() - listener->DopplerFactor() * sourceProjection));
|
||||
|
||||
WebAudioUtils::FixNaN(dopplerShift); // Avoid illegal values
|
||||
|
||||
// Limit the pitch shifting to 4 octaves up and 3 octaves down.
|
||||
dopplerShift = min(dopplerShift, 16.);
|
||||
dopplerShift = max(dopplerShift, 0.125);
|
||||
}
|
||||
}
|
||||
|
||||
return dopplerShift;
|
||||
}
|
||||
|
||||
void
|
||||
PannerNode::FindConnectedSources()
|
||||
{
|
||||
mSources.Clear();
|
||||
std::set<AudioNode*> cycleSet;
|
||||
FindConnectedSources(this, mSources, cycleSet);
|
||||
}
|
||||
|
||||
void
|
||||
PannerNode::FindConnectedSources(AudioNode* aNode,
|
||||
nsTArray<AudioBufferSourceNode*>& aSources,
|
||||
std::set<AudioNode*>& aNodesSeen)
|
||||
{
|
||||
if (!aNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsTArray<InputNode>& inputNodes = aNode->InputNodes();
|
||||
|
||||
for(unsigned i = 0; i < inputNodes.Length(); i++) {
|
||||
// Return if we find a node that we have seen already.
|
||||
if (aNodesSeen.find(inputNodes[i].mInputNode) != aNodesSeen.end()) {
|
||||
return;
|
||||
}
|
||||
aNodesSeen.insert(inputNodes[i].mInputNode);
|
||||
// Recurse
|
||||
FindConnectedSources(inputNodes[i].mInputNode, aSources, aNodesSeen);
|
||||
|
||||
// Check if this node is an AudioBufferSourceNode that still have a stream,
|
||||
// which means it has not finished playing.
|
||||
AudioBufferSourceNode* node = inputNodes[i].mInputNode->AsAudioBufferSourceNode();
|
||||
if (node && node->GetStream()) {
|
||||
aSources.AppendElement(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PannerNode::SendDopplerToSourcesIfNeeded()
|
||||
{
|
||||
// Don't bother sending the doppler shift if both the source and the listener
|
||||
// are not moving, because the doppler shift is going to be 1.0.
|
||||
if (!(Context()->Listener()->Velocity().IsZero() && mVelocity.IsZero())) {
|
||||
for(uint32_t i = 0; i < mSources.Length(); i++) {
|
||||
mSources[i]->SendDopplerShiftToStream(ComputeDopplerShift());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void DestroyMediaStream() override;
|
||||
|
||||
void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) override
|
||||
{
|
||||
if (aChannelCount > 2) {
|
||||
|
@ -103,6 +105,20 @@ public:
|
|||
SendThreeDPointParameterToStream(ORIENTATION, ConvertAudioParamTo3DP(mOrientationX, mOrientationY, mOrientationZ));
|
||||
}
|
||||
|
||||
void SetVelocity(double aX, double aY, double aZ)
|
||||
{
|
||||
if (WebAudioUtils::FuzzyEqual(mVelocity.x, aX) &&
|
||||
WebAudioUtils::FuzzyEqual(mVelocity.y, aY) &&
|
||||
WebAudioUtils::FuzzyEqual(mVelocity.z, aZ)) {
|
||||
return;
|
||||
}
|
||||
mVelocity.x = aX;
|
||||
mVelocity.y = aY;
|
||||
mVelocity.z = aZ;
|
||||
SendThreeDPointParameterToStream(VELOCITY, mVelocity);
|
||||
SendDopplerToSourcesIfNeeded();
|
||||
}
|
||||
|
||||
double RefDistance() const
|
||||
{
|
||||
return mRefDistance;
|
||||
|
@ -211,6 +227,12 @@ public:
|
|||
return mOrientationZ;
|
||||
}
|
||||
|
||||
|
||||
float ComputeDopplerShift();
|
||||
void SendDopplerToSourcesIfNeeded();
|
||||
void FindConnectedSources();
|
||||
void FindConnectedSources(AudioNode* aNode, nsTArray<AudioBufferSourceNode*>& aSources, std::set<AudioNode*>& aSeenNodes);
|
||||
|
||||
const char* NodeType() const override
|
||||
{
|
||||
return "PannerNode";
|
||||
|
@ -221,11 +243,17 @@ public:
|
|||
|
||||
private:
|
||||
explicit PannerNode(AudioContext* aContext);
|
||||
~PannerNode() = default;
|
||||
~PannerNode();
|
||||
|
||||
friend class AudioListener;
|
||||
friend class PannerNodeEngine;
|
||||
enum EngineParameters {
|
||||
LISTENER_POSITION,
|
||||
LISTENER_FRONT_VECTOR, // unit length
|
||||
LISTENER_RIGHT_VECTOR, // unit length, orthogonal to LISTENER_FRONT_VECTOR
|
||||
LISTENER_VELOCITY,
|
||||
LISTENER_DOPPLER_FACTOR,
|
||||
LISTENER_SPEED_OF_SOUND,
|
||||
PANNING_MODEL,
|
||||
DISTANCE_MODEL,
|
||||
POSITION,
|
||||
|
@ -236,6 +264,7 @@ private:
|
|||
ORIENTATIONX,
|
||||
ORIENTATIONY,
|
||||
ORIENTATIONZ,
|
||||
VELOCITY,
|
||||
REF_DISTANCE,
|
||||
MAX_DISTANCE,
|
||||
ROLLOFF_FACTOR,
|
||||
|
@ -257,6 +286,7 @@ private:
|
|||
RefPtr<AudioParam> mOrientationX;
|
||||
RefPtr<AudioParam> mOrientationY;
|
||||
RefPtr<AudioParam> mOrientationZ;
|
||||
ThreeDPoint mVelocity;
|
||||
|
||||
double mRefDistance;
|
||||
double mMaxDistance;
|
||||
|
@ -264,6 +294,10 @@ private:
|
|||
double mConeInnerAngle;
|
||||
double mConeOuterAngle;
|
||||
double mConeOuterGain;
|
||||
|
||||
// An array of all the AudioBufferSourceNode connected directly or indirectly
|
||||
// to this AudioPannerNode.
|
||||
nsTArray<AudioBufferSourceNode*> mSources;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -93,6 +93,7 @@ tags=capturestream
|
|||
[test_bug867089.html]
|
||||
[test_bug867104.html]
|
||||
[test_bug867174.html]
|
||||
[test_bug867203.html]
|
||||
[test_bug875221.html]
|
||||
[test_bug875402.html]
|
||||
[test_bug894150.html]
|
||||
|
|
|
@ -13,11 +13,18 @@ SimpleTest.waitForExplicitFinish();
|
|||
addLoadEvent(function() {
|
||||
var context = new AudioContext();
|
||||
ok("listener" in context, "AudioContext.listener should exist");
|
||||
ok(Math.abs(context.listener.dopplerFactor - 1.0) < 1e-4, "Correct default doppler factor");
|
||||
ok(Math.abs(context.listener.speedOfSound - 343.3) < 1e-4, "Correct default speed of sound value");
|
||||
context.listener.dopplerFactor = 0.5;
|
||||
ok(Math.abs(context.listener.dopplerFactor - 0.5) < 1e-4, "The doppler factor value can be changed");
|
||||
context.listener.speedOfSound = 400;
|
||||
ok(Math.abs(context.listener.speedOfSound - 400) < 1e-4, "The speed of sound can be changed");
|
||||
// The values set by the following cannot be read from script, but the
|
||||
// implementation is simple enough, so we just make sure that nothing throws.
|
||||
with (context.listener) {
|
||||
setPosition(1.0, 1.0, 1.0);
|
||||
setOrientation(1.0, 1.0, 1.0, 1.0, 1.0, 1.0);
|
||||
setVelocity(0.5, 1.0, 1.5);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Crashtest for bug 867203</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var ctx = new AudioContext();
|
||||
|
||||
var panner1 = ctx.createPanner();
|
||||
panner1.setVelocity(1, 1, 1);
|
||||
ctx.listener.setVelocity(1, 1, 1);
|
||||
(function() {
|
||||
ctx.createBufferSource().connect(panner1);
|
||||
})();
|
||||
SpecialPowers.forceGC();
|
||||
SpecialPowers.forceCC();
|
||||
ctx.createPanner();
|
||||
|
||||
ok(true, "We did not crash.");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -55,6 +55,8 @@ addLoadEvent(function() {
|
|||
near(panner.orientationY.value, 1, "setOrientation sets AudioParam properly");
|
||||
near(panner.orientationZ.value, 0, "setOrientation sets AudioParam properly");
|
||||
|
||||
panner.setVelocity(1, 1, 1);
|
||||
|
||||
source.start(0);
|
||||
SimpleTest.executeSoon(function() {
|
||||
source.stop(0);
|
||||
|
|
|
@ -12,8 +12,20 @@
|
|||
|
||||
[Pref="dom.webaudio.enabled"]
|
||||
interface AudioListener {
|
||||
|
||||
// same as OpenAL (default 1)
|
||||
[Deprecated="PannerNodeDoppler"]
|
||||
attribute double dopplerFactor;
|
||||
|
||||
// in meters / second (default 343.3)
|
||||
[Deprecated="PannerNodeDoppler"]
|
||||
attribute double speedOfSound;
|
||||
|
||||
// Uses a 3D cartesian coordinate system
|
||||
void setPosition(double x, double y, double z);
|
||||
void setOrientation(double x, double y, double z, double xUp, double yUp, double zUp);
|
||||
[Deprecated="PannerNodeDoppler"]
|
||||
void setVelocity(double x, double y, double z);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ interface PannerNode : AudioNode {
|
|||
// Uses a 3D cartesian coordinate system
|
||||
void setPosition(double x, double y, double z);
|
||||
void setOrientation(double x, double y, double z);
|
||||
[Deprecated="PannerNodeDoppler"]
|
||||
void setVelocity(double x, double y, double z);
|
||||
|
||||
// Cartesian coordinate for position
|
||||
readonly attribute AudioParam positionX;
|
||||
|
|
|
@ -12,18 +12,4 @@
|
|||
assert_false(name in window);
|
||||
}, name + " interface should not exist");
|
||||
});
|
||||
|
||||
[
|
||||
"dopplerFactor",
|
||||
"speedOfSound",
|
||||
"setVelocity"
|
||||
].forEach(name => {
|
||||
test(function() {
|
||||
assert_false(name in AudioListener.prototype);
|
||||
}, name + " member should not exist on the AudioListener.");
|
||||
});
|
||||
|
||||
test(function() {
|
||||
assert_false("setVelocity" in PannerNode.prototype);
|
||||
}, "setVelocity should not exist on PannerNodes.");
|
||||
</script>
|
||||
|
|
Загрузка…
Ссылка в новой задаче