content/media/webaudio/PannerNode.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "PannerNode.h"
     8 #include "AudioNodeEngine.h"
     9 #include "AudioNodeStream.h"
    10 #include "AudioListener.h"
    11 #include "AudioBufferSourceNode.h"
    12 #include "PlayingRefChangeHandler.h"
    13 #include "blink/HRTFPanner.h"
    14 #include "blink/HRTFDatabaseLoader.h"
    16 using WebCore::HRTFDatabaseLoader;
    17 using WebCore::HRTFPanner;
    19 namespace mozilla {
    20 namespace dom {
    22 using namespace std;
    24 NS_IMPL_CYCLE_COLLECTION_CLASS(PannerNode)
    26 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PannerNode)
    27   if (tmp->Context()) {
    28     tmp->Context()->UnregisterPannerNode(tmp);
    29   }
    30 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode)
    32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PannerNode, AudioNode)
    33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    35 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PannerNode)
    36 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
    38 NS_IMPL_ADDREF_INHERITED(PannerNode, AudioNode)
    39 NS_IMPL_RELEASE_INHERITED(PannerNode, AudioNode)
    41 class PannerNodeEngine : public AudioNodeEngine
    42 {
    43 public:
    44   explicit PannerNodeEngine(AudioNode* aNode)
    45     : AudioNodeEngine(aNode)
    46     // Please keep these default values consistent with PannerNode::PannerNode below.
    47     , mPanningModelFunction(&PannerNodeEngine::HRTFPanningFunction)
    48     , mDistanceModelFunction(&PannerNodeEngine::InverseGainFunction)
    49     , mPosition()
    50     , mOrientation(1., 0., 0.)
    51     , mVelocity()
    52     , mRefDistance(1.)
    53     , mMaxDistance(10000.)
    54     , mRolloffFactor(1.)
    55     , mConeInnerAngle(360.)
    56     , mConeOuterAngle(360.)
    57     , mConeOuterGain(0.)
    58     // These will be initialized when a PannerNode is created, so just initialize them
    59     // to some dummy values here.
    60     , mListenerDopplerFactor(0.)
    61     , mListenerSpeedOfSound(0.)
    62     , mLeftOverData(INT_MIN)
    63   {
    64     // HRTFDatabaseLoader needs to be fetched on the main thread.
    65     TemporaryRef<HRTFDatabaseLoader> loader =
    66       HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(aNode->Context()->SampleRate());
    67     mHRTFPanner = new HRTFPanner(aNode->Context()->SampleRate(), loader);
    68   }
    70   virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) MOZ_OVERRIDE
    71   {
    72     switch (aIndex) {
    73     case PannerNode::PANNING_MODEL:
    74       switch (PanningModelType(aParam)) {
    75         case PanningModelType::Equalpower:
    76           mPanningModelFunction = &PannerNodeEngine::EqualPowerPanningFunction;
    77           break;
    78         case PanningModelType::HRTF:
    79           mPanningModelFunction = &PannerNodeEngine::HRTFPanningFunction;
    80           break;
    81         default:
    82           NS_NOTREACHED("We should never see the alternate names here");
    83           break;
    84       }
    85       break;
    86     case PannerNode::DISTANCE_MODEL:
    87       switch (DistanceModelType(aParam)) {
    88         case DistanceModelType::Inverse:
    89           mDistanceModelFunction = &PannerNodeEngine::InverseGainFunction;
    90           break;
    91         case DistanceModelType::Linear:
    92           mDistanceModelFunction = &PannerNodeEngine::LinearGainFunction;
    93           break;
    94         case DistanceModelType::Exponential:
    95           mDistanceModelFunction = &PannerNodeEngine::ExponentialGainFunction;
    96           break;
    97         default:
    98           NS_NOTREACHED("We should never see the alternate names here");
    99           break;
   100       }
   101       break;
   102     default:
   103       NS_ERROR("Bad PannerNodeEngine Int32Parameter");
   104     }
   105   }
   106   virtual void SetThreeDPointParameter(uint32_t aIndex, const ThreeDPoint& aParam) MOZ_OVERRIDE
   107   {
   108     switch (aIndex) {
   109     case PannerNode::LISTENER_POSITION: mListenerPosition = aParam; break;
   110     case PannerNode::LISTENER_FRONT_VECTOR: mListenerFrontVector = aParam; break;
   111     case PannerNode::LISTENER_RIGHT_VECTOR: mListenerRightVector = aParam; break;
   112     case PannerNode::LISTENER_VELOCITY: mListenerVelocity = aParam; break;
   113     case PannerNode::POSITION: mPosition = aParam; break;
   114     case PannerNode::ORIENTATION: mOrientation = aParam; break;
   115     case PannerNode::VELOCITY: mVelocity = aParam; break;
   116     default:
   117       NS_ERROR("Bad PannerNodeEngine ThreeDPointParameter");
   118     }
   119   }
   120   virtual void SetDoubleParameter(uint32_t aIndex, double aParam) MOZ_OVERRIDE
   121   {
   122     switch (aIndex) {
   123     case PannerNode::LISTENER_DOPPLER_FACTOR: mListenerDopplerFactor = aParam; break;
   124     case PannerNode::LISTENER_SPEED_OF_SOUND: mListenerSpeedOfSound = aParam; break;
   125     case PannerNode::REF_DISTANCE: mRefDistance = aParam; break;
   126     case PannerNode::MAX_DISTANCE: mMaxDistance = aParam; break;
   127     case PannerNode::ROLLOFF_FACTOR: mRolloffFactor = aParam; break;
   128     case PannerNode::CONE_INNER_ANGLE: mConeInnerAngle = aParam; break;
   129     case PannerNode::CONE_OUTER_ANGLE: mConeOuterAngle = aParam; break;
   130     case PannerNode::CONE_OUTER_GAIN: mConeOuterGain = aParam; break;
   131     default:
   132       NS_ERROR("Bad PannerNodeEngine DoubleParameter");
   133     }
   134   }
   136   virtual void ProcessBlock(AudioNodeStream* aStream,
   137                             const AudioChunk& aInput,
   138                             AudioChunk* aOutput,
   139                             bool *aFinished) MOZ_OVERRIDE
   140   {
   141     if (aInput.IsNull()) {
   142       // mLeftOverData != INT_MIN means that the panning model was HRTF and a
   143       // tail-time reference was added.  Even if the model is now equalpower,
   144       // the reference will need to be removed.
   145       if (mLeftOverData > 0 &&
   146           mPanningModelFunction == &PannerNodeEngine::HRTFPanningFunction) {
   147         mLeftOverData -= WEBAUDIO_BLOCK_SIZE;
   148       } else {
   149         if (mLeftOverData != INT_MIN) {
   150           mLeftOverData = INT_MIN;
   151           mHRTFPanner->reset();
   153           nsRefPtr<PlayingRefChangeHandler> refchanged =
   154             new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
   155           aStream->Graph()->
   156             DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
   157         }
   158         *aOutput = aInput;
   159         return;
   160       }
   161     } else if (mPanningModelFunction == &PannerNodeEngine::HRTFPanningFunction) {
   162       if (mLeftOverData == INT_MIN) {
   163         nsRefPtr<PlayingRefChangeHandler> refchanged =
   164           new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
   165         aStream->Graph()->
   166           DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
   167       }
   168       mLeftOverData = mHRTFPanner->maxTailFrames();
   169     }
   171     (this->*mPanningModelFunction)(aInput, aOutput);
   172   }
   174   void ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation);
   175   float ComputeConeGain();
   176   // Compute how much the distance contributes to the gain reduction.
   177   float ComputeDistanceGain();
   179   void GainMonoToStereo(const AudioChunk& aInput, AudioChunk* aOutput,
   180                         float aGainL, float aGainR);
   181   void GainStereoToStereo(const AudioChunk& aInput, AudioChunk* aOutput,
   182                           float aGainL, float aGainR, double aAzimuth);
   184   void EqualPowerPanningFunction(const AudioChunk& aInput, AudioChunk* aOutput);
   185   void HRTFPanningFunction(const AudioChunk& aInput, AudioChunk* aOutput);
   187   float LinearGainFunction(float aDistance);
   188   float InverseGainFunction(float aDistance);
   189   float ExponentialGainFunction(float aDistance);
   191   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   192   {
   193     size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
   194     if (mHRTFPanner) {
   195       amount += mHRTFPanner->sizeOfIncludingThis(aMallocSizeOf);
   196     }
   198     return amount;
   199   }
   201   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   202   {
   203     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   204   }
   206   nsAutoPtr<HRTFPanner> mHRTFPanner;
   207   typedef void (PannerNodeEngine::*PanningModelFunction)(const AudioChunk& aInput, AudioChunk* aOutput);
   208   PanningModelFunction mPanningModelFunction;
   209   typedef float (PannerNodeEngine::*DistanceModelFunction)(float aDistance);
   210   DistanceModelFunction mDistanceModelFunction;
   211   ThreeDPoint mPosition;
   212   ThreeDPoint mOrientation;
   213   ThreeDPoint mVelocity;
   214   double mRefDistance;
   215   double mMaxDistance;
   216   double mRolloffFactor;
   217   double mConeInnerAngle;
   218   double mConeOuterAngle;
   219   double mConeOuterGain;
   220   ThreeDPoint mListenerPosition;
   221   ThreeDPoint mListenerFrontVector;
   222   ThreeDPoint mListenerRightVector;
   223   ThreeDPoint mListenerVelocity;
   224   double mListenerDopplerFactor;
   225   double mListenerSpeedOfSound;
   226   int mLeftOverData;
   227 };
   229 PannerNode::PannerNode(AudioContext* aContext)
   230   : AudioNode(aContext,
   231               2,
   232               ChannelCountMode::Clamped_max,
   233               ChannelInterpretation::Speakers)
   234   // Please keep these default values consistent with PannerNodeEngine::PannerNodeEngine above.
   235   , mPanningModel(PanningModelType::HRTF)
   236   , mDistanceModel(DistanceModelType::Inverse)
   237   , mPosition()
   238   , mOrientation(1., 0., 0.)
   239   , mVelocity()
   240   , mRefDistance(1.)
   241   , mMaxDistance(10000.)
   242   , mRolloffFactor(1.)
   243   , mConeInnerAngle(360.)
   244   , mConeOuterAngle(360.)
   245   , mConeOuterGain(0.)
   246 {
   247   mStream = aContext->Graph()->CreateAudioNodeStream(new PannerNodeEngine(this),
   248                                                      MediaStreamGraph::INTERNAL_STREAM);
   249   // We should register once we have set up our stream and engine.
   250   Context()->Listener()->RegisterPannerNode(this);
   251 }
   253 PannerNode::~PannerNode()
   254 {
   255   if (Context()) {
   256     Context()->UnregisterPannerNode(this);
   257   }
   258 }
   260 size_t
   261 PannerNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   262 {
   263   size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
   264   amount += mSources.SizeOfExcludingThis(aMallocSizeOf);
   265   return amount;
   266 }
   268 size_t
   269 PannerNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   270 {
   271   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   272 }
   274 JSObject*
   275 PannerNode::WrapObject(JSContext* aCx)
   276 {
   277   return PannerNodeBinding::Wrap(aCx, this);
   278 }
   280 void PannerNode::DestroyMediaStream()
   281 {
   282   if (Context()) {
   283     Context()->UnregisterPannerNode(this);
   284   }
   285   AudioNode::DestroyMediaStream();
   286 }
   288 // Those three functions are described in the spec.
   289 float
   290 PannerNodeEngine::LinearGainFunction(float aDistance)
   291 {
   292   return 1 - mRolloffFactor * (aDistance - mRefDistance) / (mMaxDistance - mRefDistance);
   293 }
   295 float
   296 PannerNodeEngine::InverseGainFunction(float aDistance)
   297 {
   298   return mRefDistance / (mRefDistance + mRolloffFactor * (aDistance - mRefDistance));
   299 }
   301 float
   302 PannerNodeEngine::ExponentialGainFunction(float aDistance)
   303 {
   304   return pow(aDistance / mRefDistance, -mRolloffFactor);
   305 }
   307 void
   308 PannerNodeEngine::HRTFPanningFunction(const AudioChunk& aInput,
   309                                       AudioChunk* aOutput)
   310 {
   311   // The output of this node is always stereo, no matter what the inputs are.
   312   AllocateAudioBlock(2, aOutput);
   314   float azimuth, elevation;
   315   ComputeAzimuthAndElevation(azimuth, elevation);
   317   AudioChunk input = aInput;
   318   // Gain is applied before the delay and convolution of the HRTF
   319   input.mVolume *= ComputeConeGain() * ComputeDistanceGain();
   321   mHRTFPanner->pan(azimuth, elevation, &input, aOutput);
   322 }
   324 void
   325 PannerNodeEngine::EqualPowerPanningFunction(const AudioChunk& aInput,
   326                                             AudioChunk* aOutput)
   327 {
   328   float azimuth, elevation, gainL, gainR, normalizedAzimuth, distanceGain, coneGain;
   329   int inputChannels = aInput.mChannelData.Length();
   331   // If both the listener are in the same spot, and no cone gain is specified,
   332   // this node is noop.
   333   if (mListenerPosition == mPosition &&
   334       mConeInnerAngle == 360 &&
   335       mConeOuterAngle == 360) {
   336     *aOutput = aInput;
   337     return;
   338   }
   340   // The output of this node is always stereo, no matter what the inputs are.
   341   AllocateAudioBlock(2, aOutput);
   343   ComputeAzimuthAndElevation(azimuth, elevation);
   344   coneGain = ComputeConeGain();
   346   // The following algorithm is described in the spec.
   347   // Clamp azimuth in the [-90, 90] range.
   348   azimuth = min(180.f, max(-180.f, azimuth));
   350   // Wrap around
   351   if (azimuth < -90.f) {
   352     azimuth = -180.f - azimuth;
   353   } else if (azimuth > 90) {
   354     azimuth = 180.f - azimuth;
   355   }
   357   // Normalize the value in the [0, 1] range.
   358   if (inputChannels == 1) {
   359     normalizedAzimuth = (azimuth + 90.f) / 180.f;
   360   } else {
   361     if (azimuth <= 0) {
   362       normalizedAzimuth = (azimuth + 90.f) / 90.f;
   363     } else {
   364       normalizedAzimuth = azimuth / 90.f;
   365     }
   366   }
   368   distanceGain = ComputeDistanceGain();
   370   // Actually compute the left and right gain.
   371   gainL = cos(0.5 * M_PI * normalizedAzimuth);
   372   gainR = sin(0.5 * M_PI * normalizedAzimuth);
   374   // Compute the output.
   375   if (inputChannels == 1) {
   376     GainMonoToStereo(aInput, aOutput, gainL, gainR);
   377   } else {
   378     GainStereoToStereo(aInput, aOutput, gainL, gainR, azimuth);
   379   }
   381   aOutput->mVolume = aInput.mVolume * distanceGain * coneGain;
   382 }
   384 void
   385 PannerNodeEngine::GainMonoToStereo(const AudioChunk& aInput, AudioChunk* aOutput,
   386                                    float aGainL, float aGainR)
   387 {
   388   float* outputL = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
   389   float* outputR = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[1]));
   390   const float* input = static_cast<float*>(const_cast<void*>(aInput.mChannelData[0]));
   392   AudioBlockPanMonoToStereo(input, aGainL, aGainR, outputL, outputR);
   393 }
   395 void
   396 PannerNodeEngine::GainStereoToStereo(const AudioChunk& aInput, AudioChunk* aOutput,
   397                                      float aGainL, float aGainR, double aAzimuth)
   398 {
   399   float* outputL = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
   400   float* outputR = static_cast<float*>(const_cast<void*>(aOutput->mChannelData[1]));
   401   const float* inputL = static_cast<float*>(const_cast<void*>(aInput.mChannelData[0]));
   402   const float* inputR = static_cast<float*>(const_cast<void*>(aInput.mChannelData[1]));
   404   AudioBlockPanStereoToStereo(inputL, inputR, aGainL, aGainR, aAzimuth <= 0, outputL, outputR);
   405 }
   407 // This algorithm is specified in the webaudio spec.
   408 void
   409 PannerNodeEngine::ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation)
   410 {
   411   ThreeDPoint sourceListener = mPosition - mListenerPosition;
   413   if (sourceListener.IsZero()) {
   414     aAzimuth = 0.0;
   415     aElevation = 0.0;
   416     return;
   417   }
   419   sourceListener.Normalize();
   421   // Project the source-listener vector on the x-z plane.
   422   const ThreeDPoint& listenerFront = mListenerFrontVector;
   423   const ThreeDPoint& listenerRight = mListenerRightVector;
   424   ThreeDPoint up = listenerRight.CrossProduct(listenerFront);
   426   double upProjection = sourceListener.DotProduct(up);
   427   aElevation = 90 - 180 * acos(upProjection) / M_PI;
   429   if (aElevation > 90) {
   430     aElevation = 180 - aElevation;
   431   } else if (aElevation < -90) {
   432     aElevation = -180 - aElevation;
   433   }
   435   ThreeDPoint projectedSource = sourceListener - up * upProjection;
   436   if (projectedSource.IsZero()) {
   437     // source - listener direction is up or down.
   438     aAzimuth = 0.0;
   439     return;
   440   }
   441   projectedSource.Normalize();
   443   // Actually compute the angle, and convert to degrees
   444   double projection = projectedSource.DotProduct(listenerRight);
   445   aAzimuth = 180 * acos(projection) / M_PI;
   447   // Compute whether the source is in front or behind the listener.
   448   double frontBack = projectedSource.DotProduct(listenerFront);
   449   if (frontBack < 0) {
   450     aAzimuth = 360 - aAzimuth;
   451   }
   452   // Rotate the azimuth so it is relative to the listener front vector instead
   453   // of the right vector.
   454   if ((aAzimuth >= 0) && (aAzimuth <= 270)) {
   455     aAzimuth = 90 - aAzimuth;
   456   } else {
   457     aAzimuth = 450 - aAzimuth;
   458   }
   459 }
   461 // This algorithm is described in the WebAudio spec.
   462 float
   463 PannerNodeEngine::ComputeConeGain()
   464 {
   465   // Omnidirectional source
   466   if (mOrientation.IsZero() || ((mConeInnerAngle == 360) && (mConeOuterAngle == 360))) {
   467     return 1;
   468   }
   470   // Normalized source-listener vector
   471   ThreeDPoint sourceToListener = mListenerPosition - mPosition;
   472   sourceToListener.Normalize();
   474   // Angle between the source orientation vector and the source-listener vector
   475   double dotProduct = sourceToListener.DotProduct(mOrientation);
   476   double angle = 180 * acos(dotProduct) / M_PI;
   477   double absAngle = fabs(angle);
   479   // Divide by 2 here since API is entire angle (not half-angle)
   480   double absInnerAngle = fabs(mConeInnerAngle) / 2;
   481   double absOuterAngle = fabs(mConeOuterAngle) / 2;
   482   double gain = 1;
   484   if (absAngle <= absInnerAngle) {
   485     // No attenuation
   486     gain = 1;
   487   } else if (absAngle >= absOuterAngle) {
   488     // Max attenuation
   489     gain = mConeOuterGain;
   490   } else {
   491     // Between inner and outer cones
   492     // inner -> outer, x goes from 0 -> 1
   493     double x = (absAngle - absInnerAngle) / (absOuterAngle - absInnerAngle);
   494     gain = (1 - x) + mConeOuterGain * x;
   495   }
   497   return gain;
   498 }
   500 float
   501 PannerNodeEngine::ComputeDistanceGain()
   502 {
   503   ThreeDPoint distanceVec = mPosition - mListenerPosition;
   504   float distance = sqrt(distanceVec.DotProduct(distanceVec));
   505   return (this->*mDistanceModelFunction)(distance);
   506 }
   508 float
   509 PannerNode::ComputeDopplerShift()
   510 {
   511   double dopplerShift = 1.0; // Initialize to default value
   513   AudioListener* listener = Context()->Listener();
   515   if (listener->DopplerFactor() > 0) {
   516     // Don't bother if both source and listener have no velocity.
   517     if (!mVelocity.IsZero() || !listener->Velocity().IsZero()) {
   518       // Calculate the source to listener vector.
   519       ThreeDPoint sourceToListener = mPosition - listener->Velocity();
   521       double sourceListenerMagnitude = sourceToListener.Magnitude();
   523       double listenerProjection = sourceToListener.DotProduct(listener->Velocity()) / sourceListenerMagnitude;
   524       double sourceProjection = sourceToListener.DotProduct(mVelocity) / sourceListenerMagnitude;
   526       listenerProjection = -listenerProjection;
   527       sourceProjection = -sourceProjection;
   529       double scaledSpeedOfSound = listener->DopplerFactor() / listener->DopplerFactor();
   530       listenerProjection = min(listenerProjection, scaledSpeedOfSound);
   531       sourceProjection = min(sourceProjection, scaledSpeedOfSound);
   533       dopplerShift = ((listener->SpeedOfSound() - listener->DopplerFactor() * listenerProjection) / (listener->SpeedOfSound() - listener->DopplerFactor() * sourceProjection));
   535       WebAudioUtils::FixNaN(dopplerShift); // Avoid illegal values
   537       // Limit the pitch shifting to 4 octaves up and 3 octaves down.
   538       dopplerShift = min(dopplerShift, 16.);
   539       dopplerShift = max(dopplerShift, 0.125);
   540     }
   541   }
   543   return dopplerShift;
   544 }
   546 void
   547 PannerNode::FindConnectedSources()
   548 {
   549   mSources.Clear();
   550   std::set<AudioNode*> cycleSet;
   551   FindConnectedSources(this, mSources, cycleSet);
   552 }
   554 void
   555 PannerNode::FindConnectedSources(AudioNode* aNode,
   556                                  nsTArray<AudioBufferSourceNode*>& aSources,
   557                                  std::set<AudioNode*>& aNodesSeen)
   558 {
   559   if (!aNode) {
   560     return;
   561   }
   563   const nsTArray<InputNode>& inputNodes = aNode->InputNodes();
   565   for(unsigned i = 0; i < inputNodes.Length(); i++) {
   566     // Return if we find a node that we have seen already.
   567     if (aNodesSeen.find(inputNodes[i].mInputNode) != aNodesSeen.end()) {
   568       return;
   569     }
   570     aNodesSeen.insert(inputNodes[i].mInputNode);
   571     // Recurse
   572     FindConnectedSources(inputNodes[i].mInputNode, aSources, aNodesSeen);
   574     // Check if this node is an AudioBufferSourceNode
   575     AudioBufferSourceNode* node = inputNodes[i].mInputNode->AsAudioBufferSourceNode();
   576     if (node) {
   577       aSources.AppendElement(node);
   578     }
   579   }
   580 }
   582 void
   583 PannerNode::SendDopplerToSourcesIfNeeded()
   584 {
   585   // Don't bother sending the doppler shift if both the source and the listener
   586   // are not moving, because the doppler shift is going to be 1.0.
   587   if (!(Context()->Listener()->Velocity().IsZero() && mVelocity.IsZero())) {
   588     for(uint32_t i = 0; i < mSources.Length(); i++) {
   589       mSources[i]->SendDopplerShiftToStream(ComputeDopplerShift());
   590     }
   591   }
   592 }
   595 }
   596 }

mercurial