Bug 898291 - Skip HRTF panner processing when input has been null long enough for output to be null. r=ehsan, a=lsblakk
authorKarl Tomlinson <karlt+@karlt.net>
Fri, 25 Oct 2013 14:05:43 +1300
changeset 286411 8be8c7920b1156bfd223bf90a802e89d43c96abc
parent 286410 da6663c9edcd718f07b3cc54c353367fe3847342
child 286412 5e64fdaa360ce1793bac47799b3e100639adf7c1
push id218
push userryanvm@gmail.com
push dateWed, 16 Dec 2015 22:58:33 +0000
reviewersehsan, lsblakk
bugs898291
milestone26.0
Bug 898291 - Skip HRTF panner processing when input has been null long enough for output to be null. r=ehsan, a=lsblakk
content/media/webaudio/PannerNode.cpp
content/media/webaudio/blink/HRTFPanner.cpp
content/media/webaudio/blink/HRTFPanner.h
--- a/content/media/webaudio/PannerNode.cpp
+++ b/content/media/webaudio/PannerNode.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PannerNode.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "AudioListener.h"
 #include "AudioBufferSourceNode.h"
+#include "PlayingRefChangeHandler.h"
 #include "blink/HRTFPanner.h"
 #include "blink/HRTFDatabaseLoader.h"
 
 using WebCore::HRTFDatabaseLoader;
 using WebCore::HRTFPanner;
 
 namespace mozilla {
 namespace dom {
@@ -53,16 +54,17 @@ public:
     , 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)
   {
     // HRTFDatabaseLoader needs to be fetched on the main thread.
     TemporaryRef<HRTFDatabaseLoader> loader =
       HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(aNode->Context()->SampleRate());
     mHRTFPanner = new HRTFPanner(aNode->Context()->SampleRate(), loader);
   }
 
   virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) MOZ_OVERRIDE
@@ -131,16 +133,45 @@ public:
     }
   }
 
   virtual void ProduceAudioBlock(AudioNodeStream* aStream,
                                  const AudioChunk& aInput,
                                  AudioChunk* aOutput,
                                  bool *aFinished) MOZ_OVERRIDE
   {
+    if (aInput.IsNull()) {
+      // mLeftOverData != INT_MIN means that the panning model was HRTF and a
+      // tail-time reference was added.  Even if the model is now equalpower,
+      // the reference will need to be removed.
+      if (mLeftOverData > 0) {
+        mLeftOverData -= WEBAUDIO_BLOCK_SIZE;
+      } else {
+        if (mLeftOverData != INT_MIN) {
+          mLeftOverData = INT_MIN;
+          mHRTFPanner->reset();
+
+          nsRefPtr<PlayingRefChangeHandler> refchanged =
+            new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
+          aStream->Graph()->
+            DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
+        }
+        *aOutput = aInput;
+        return;
+      }
+    } else if (mPanningModelFunction == &PannerNodeEngine::HRTFPanningFunction) {
+      if (mLeftOverData == INT_MIN) {
+        nsRefPtr<PlayingRefChangeHandler> refchanged =
+          new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
+        aStream->Graph()->
+          DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget());
+      }
+      mLeftOverData = mHRTFPanner->maxTailFrames();
+    }
+
     (this->*mPanningModelFunction)(aInput, aOutput);
   }
 
   void ComputeAzimuthAndElevation(float& aAzimuth, float& aElevation);
   void DistanceAndConeGain(AudioChunk* aChunk, float aGain);
   float ComputeConeGain();
   // Compute how much the distance contributes to the gain reduction.
   float ComputeDistanceGain();
@@ -172,16 +203,17 @@ public:
   double mConeOuterAngle;
   double mConeOuterGain;
   ThreeDPoint mListenerPosition;
   ThreeDPoint mListenerFrontVector;
   ThreeDPoint mListenerRightVector;
   ThreeDPoint mListenerVelocity;
   double mListenerDopplerFactor;
   double mListenerSpeedOfSound;
+  int mLeftOverData;
 };
 
 PannerNode::PannerNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Clamped_max,
               ChannelInterpretation::Speakers)
   // Please keep these default values consistent with PannerNodeEngine::PannerNodeEngine above.
@@ -272,21 +304,16 @@ PannerNodeEngine::HRTFPanningFunction(co
 
   mHRTFPanner->pan(azimuth, elevation, &input, aOutput, WEBAUDIO_BLOCK_SIZE);
 }
 
 void
 PannerNodeEngine::EqualPowerPanningFunction(const AudioChunk& aInput,
                                             AudioChunk* aOutput)
 {
-  if (aInput.IsNull()) {
-    *aOutput = aInput;
-    return;
-  }
-
   float azimuth, elevation, gainL, gainR, normalizedAzimuth, distanceGain, coneGain;
   int inputChannels = aInput.mChannelData.Length();
 
   // If both the listener are in the same spot, and no cone gain is specified,
   // this node is noop.
   if (mListenerPosition == mPosition &&
       mConeInnerAngle == 360 &&
       mConeOuterAngle == 360) {
--- a/content/media/webaudio/blink/HRTFPanner.cpp
+++ b/content/media/webaudio/blink/HRTFPanner.cpp
@@ -285,24 +285,21 @@ void HRTFPanner::pan(double desiredAzimu
                 m_crossfadeSelection = CrossfadeSelection1;
                 m_crossfadeX = 0;
                 m_crossfadeIncr = 0;
             }
         }
     }
 }
 
-double HRTFPanner::tailTime() const
+int HRTFPanner::maxTailFrames() const
 {
-    // Because HRTFPanner is implemented with a DelayKernel and a FFTConvolver, the tailTime of the HRTFPanner
-    // is the sum of the tailTime of the DelayKernel and the tailTime of the FFTConvolver, which is MaxDelayTimeSeconds
-    // and fftSize() / 2, respectively.
-    return MaxDelayTimeSeconds + (fftSize() / 2) / static_cast<double>(sampleRate());
-}
-
-double HRTFPanner::latencyTime() const
-{
-    // The latency of a FFTConvolver is also fftSize() / 2, and is in addition to its tailTime of the
-    // same value.
-    return (fftSize() / 2) / static_cast<double>(sampleRate());
+    // Although the ideal tail time would be the length of the impulse
+    // response, there is additional tail time from the approximations in the
+    // implementation.  Because HRTFPanner is implemented with a DelayKernel
+    // and a FFTConvolver, the tailTime of the HRTFPanner is the sum of the
+    // tailTime of the DelayKernel and the tailTime of the FFTConvolver.
+    // The FFTConvolver has a tail time of fftSize(), including latency of
+    // fftSize()/2.
+    return m_delayLineL.MaxDelayFrames() + fftSize();
 }
 
 } // namespace WebCore
--- a/content/media/webaudio/blink/HRTFPanner.h
+++ b/content/media/webaudio/blink/HRTFPanner.h
@@ -46,18 +46,17 @@ public:
     // framesToProcess must be a power of 2 and greater than 128
     void pan(double azimuth, double elevation, const AudioChunk* inputBus, AudioChunk* outputBus, mozilla::TrackTicks framesToProcess);
     void reset();
 
     size_t fftSize() const { return m_convolverL1.fftSize(); }
 
     float sampleRate() const { return m_sampleRate; }
 
-    double tailTime() const;
-    double latencyTime() const;
+    int maxTailFrames() const;
 
 private:
     // Given an azimuth angle in the range -180 -> +180, returns the corresponding azimuth index for the database,
     // and azimuthBlend which is an interpolation value from 0 -> 1.
     int calculateDesiredAzimuthIndexAndBlend(double azimuth, double& azimuthBlend);
 
     mozilla::RefPtr<HRTFDatabaseLoader> m_databaseLoader;