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:
Andreea Pavel 2018-07-20 17:13:20 +03:00
Родитель fced036309
Коммит 98338c6ff5
15 изменённых файлов: 415 добавлений и 154 удалений

Просмотреть файл

@ -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>