Bug 873553 - Part 5: Port AudioBufferSourceNodeEngine to use the stream's sampling rate; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 24 May 2013 13:13:31 -0400
changeset 132925 7efdd15be9c7cf8c2d0adf8643b5556cc1a1f5d2
parent 132924 59f25c1db41453d11620888b9499ebce5eb0512a
child 132926 d34c29fe4edaa9e948c184f2b79224e735638aa0
push id24727
push userphilringnalda@gmail.com
push dateSun, 26 May 2013 04:02:45 +0000
treeherdermozilla-central@0fed3377c839 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs873553
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 873553 - Part 5: Port AudioBufferSourceNodeEngine to use the stream's sampling rate; r=roc
content/media/webaudio/AudioBufferSourceNode.cpp
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -73,17 +73,17 @@ public:
     switch (aIndex) {
     case AudioBufferSourceNode::PLAYBACKRATE:
       mPlaybackRateTimeline = aValue;
       // If we have a simple value that is 1.0 (i.e. intrinsic speed), and our
       // input buffer is already at the ideal audio rate, and we have a
       // resampler, we can release it.
       if (mResampler && mPlaybackRateTimeline.HasSimpleValue() &&
           mPlaybackRateTimeline.GetValue() == 1.0 &&
-          mBufferSampleRate == IdealAudioRate()) {
+          mBufferSampleRate == aSampleRate) {
         speex_resampler_destroy(mResampler);
         mResampler = nullptr;
       }
       WebAudioUtils::ConvertAudioParamToTicks(mPlaybackRateTimeline, nullptr, mDestination);
       break;
     case AudioBufferSourceNode::GAIN:
       SetGainParameter(aValue);
       break;
@@ -123,27 +123,27 @@ public:
       NS_ERROR("Bad AudioBufferSourceNodeEngine Int32Parameter");
     }
   }
   virtual void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
   {
     mBuffer = aBuffer;
   }
 
-  SpeexResamplerState* Resampler(uint32_t aChannels)
+  SpeexResamplerState* Resampler(AudioNodeStream* aStream, uint32_t aChannels)
   {
     if (aChannels != mChannels && mResampler) {
       speex_resampler_destroy(mResampler);
       mResampler = nullptr;
     }
 
     if (!mResampler) {
       mChannels = aChannels;
       mResampler = speex_resampler_init(mChannels, mBufferSampleRate,
-                                        ComputeFinalOutSampleRate(),
+                                        ComputeFinalOutSampleRate(aStream->SampleRate()),
                                         SPEEX_RESAMPLER_QUALITY_DEFAULT,
                                         nullptr);
     }
     return mResampler;
   }
 
   // Borrow a full buffer of size WEBAUDIO_BLOCK_SIZE from the source buffer
   // at offset aSourceOffset.  This avoids copying memory.
@@ -176,37 +176,39 @@ public:
     }
   }
 
   // Resamples input data to an output buffer, according to |mBufferSampleRate| and
   // the playbackRate.
   // The number of frames consumed/produced depends on the amount of space
   // remaining in both the input and output buffer, and the playback rate (that
   // is, the ratio between the output samplerate and the input samplerate).
-  void CopyFromInputBufferWithResampling(AudioChunk* aOutput,
+  void CopyFromInputBufferWithResampling(AudioNodeStream* aStream,
+                                         AudioChunk* aOutput,
                                          uint32_t aChannels,
                                          uintptr_t aSourceOffset,
                                          uintptr_t aBufferOffset,
                                          uint32_t aAvailableInInputBuffer,
                                          uint32_t& aFramesRead,
                                          uint32_t& aFramesWritten) {
-    double finalPlaybackRate = static_cast<double>(mBufferSampleRate) / ComputeFinalOutSampleRate();
+    double finalPlaybackRate =
+      static_cast<double>(mBufferSampleRate) / ComputeFinalOutSampleRate(aStream->SampleRate());
     uint32_t availableInOuputBuffer = WEBAUDIO_BLOCK_SIZE - aBufferOffset;
     uint32_t inputSamples, outputSamples;
 
     // Check if we are short on input or output buffer.
     if (aAvailableInInputBuffer < availableInOuputBuffer * finalPlaybackRate) {
       outputSamples = ceil(aAvailableInInputBuffer / finalPlaybackRate);
       inputSamples = aAvailableInInputBuffer;
     } else {
       inputSamples = ceil(availableInOuputBuffer * finalPlaybackRate);
       outputSamples = availableInOuputBuffer;
     }
 
-    SpeexResamplerState* resampler = Resampler(aChannels);
+    SpeexResamplerState* resampler = Resampler(aStream, aChannels);
 
     for (uint32_t i = 0; i < aChannels; ++i) {
       uint32_t inSamples = inputSamples;
       uint32_t outSamples = outputSamples;
 
       const float* inputData = mBuffer->GetData(i) + aSourceOffset;
       float* outputData =
         static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
@@ -253,101 +255,102 @@ public:
    * Copy as many frames as possible from the source buffer to aOutput, and
    * advance aOffsetWithinBlock and aCurrentPosition based on how many frames
    * we copy.  This will never advance aOffsetWithinBlock past
    * WEBAUDIO_BLOCK_SIZE, or aCurrentPosition past mStop.  It takes data from
    * the buffer at aBufferOffset, and never takes more data than aBufferMax.
    * This function knows when it needs to allocate the output buffer, and also
    * optimizes the case where it can avoid memory allocations.
    */
-  void CopyFromBuffer(AudioChunk* aOutput,
+  void CopyFromBuffer(AudioNodeStream* aStream,
+                      AudioChunk* aOutput,
                       uint32_t aChannels,
                       uint32_t* aOffsetWithinBlock,
                       TrackTicks* aCurrentPosition,
                       uint32_t aBufferOffset,
                       uint32_t aBufferMax)
   {
     uint32_t numFrames = std::min(std::min(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                                            aBufferMax - aBufferOffset),
                                   uint32_t(mStop - *aCurrentPosition));
-    if (numFrames == WEBAUDIO_BLOCK_SIZE && !ShouldResample()) {
+    if (numFrames == WEBAUDIO_BLOCK_SIZE && !ShouldResample(aStream->SampleRate())) {
       BorrowFromInputBuffer(aOutput, aChannels, aBufferOffset);
       *aOffsetWithinBlock += numFrames;
       *aCurrentPosition += numFrames;
       mPosition += numFrames;
     } else {
       if (aOutput->IsNull()) {
         MOZ_ASSERT(*aOffsetWithinBlock == 0);
         AllocateAudioBlock(aChannels, aOutput);
       }
-      if (!ShouldResample()) {
+      if (!ShouldResample(aStream->SampleRate())) {
         CopyFromInputBuffer(aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, numFrames);
         *aOffsetWithinBlock += numFrames;
         *aCurrentPosition += numFrames;
         mPosition += numFrames;
       } else {
         uint32_t framesRead, framesWritten, availableInInputBuffer;
 
         availableInInputBuffer = aBufferMax - aBufferOffset;
 
-        CopyFromInputBufferWithResampling(aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, availableInInputBuffer, framesRead, framesWritten);
+        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, availableInInputBuffer, framesRead, framesWritten);
         *aOffsetWithinBlock += framesWritten;
         *aCurrentPosition += framesRead;
         mPosition += framesRead;
       }
     }
   }
 
   TrackTicks GetPosition(AudioNodeStream* aStream)
   {
     if (aStream->GetCurrentPosition() < mStart) {
       return aStream->GetCurrentPosition();
     }
     return mStart + mPosition;
   }
 
-  uint32_t ComputeFinalOutSampleRate()
+  uint32_t ComputeFinalOutSampleRate(TrackRate aStreamSampleRate)
   {
     if (mPlaybackRate <= 0 || mPlaybackRate != mPlaybackRate) {
       mPlaybackRate = 1.0f;
     }
     if (mDopplerShift <= 0 || mDopplerShift != mDopplerShift) {
       mDopplerShift = 1.0f;
     }
-    return WebAudioUtils::TruncateFloatToInt<uint32_t>(IdealAudioRate() /
+    return WebAudioUtils::TruncateFloatToInt<uint32_t>(aStreamSampleRate /
                                                        (mPlaybackRate * mDopplerShift));
   }
 
-  bool ShouldResample() const
+  bool ShouldResample(TrackRate aStreamSampleRate) const
   {
     return !(mPlaybackRate == 1.0 &&
              mDopplerShift == 1.0 &&
-             mBufferSampleRate == IdealAudioRate());
+             mBufferSampleRate == aStreamSampleRate);
   }
 
   void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels)
   {
     if (mPlaybackRateTimeline.HasSimpleValue()) {
       mPlaybackRate = mPlaybackRateTimeline.GetValue();
     } else {
       mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition());
     }
 
     // Make sure the playback rate and the doppler shift are something
     // our resampler can work with.
-    if (ComputeFinalOutSampleRate() == 0) {
+    if (ComputeFinalOutSampleRate(aStream->SampleRate()) == 0) {
       mPlaybackRate = 1.0;
       mDopplerShift = 1.0;
     }
 
     uint32_t currentOutSampleRate, currentInSampleRate;
-    if (ShouldResample()) {
-      SpeexResamplerState* resampler = Resampler(aChannels);
+    if (ShouldResample(aStream->SampleRate())) {
+      SpeexResamplerState* resampler = Resampler(aStream, aChannels);
       speex_resampler_get_rate(resampler, &currentInSampleRate, &currentOutSampleRate);
-      uint32_t finalSampleRate = ComputeFinalOutSampleRate();
+      uint32_t finalSampleRate = ComputeFinalOutSampleRate(aStream->SampleRate());
       if (currentOutSampleRate != finalSampleRate) {
         speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate);
         speex_resampler_skip_zeros(mResampler);
       }
     }
   }
 
   virtual void ProduceAudioBlock(AudioNodeStream* aStream,
@@ -379,24 +382,24 @@ public:
       }
       if (currentPosition < mStart) {
         FillWithZeroes(aOutput, channels, &written, &currentPosition, mStart);
         continue;
       }
       TrackTicks t = currentPosition - mStart;
       if (mLoop) {
         if (mOffset + t < mLoopEnd) {
-          CopyFromBuffer(aOutput, channels, &written, &currentPosition, mOffset + t, mLoopEnd);
+          CopyFromBuffer(aStream, aOutput, channels, &written, &currentPosition, mOffset + t, mLoopEnd);
         } else {
           uint32_t offsetInLoop = (mOffset + t - mLoopEnd) % (mLoopEnd - mLoopStart);
-          CopyFromBuffer(aOutput, channels, &written, &currentPosition, mLoopStart + offsetInLoop, mLoopEnd);
+          CopyFromBuffer(aStream, aOutput, channels, &written, &currentPosition, mLoopStart + offsetInLoop, mLoopEnd);
         }
       } else {
         if (mOffset + t < mDuration) {
-          CopyFromBuffer(aOutput, channels, &written, &currentPosition, mOffset + t, mDuration);
+          CopyFromBuffer(aStream, aOutput, channels, &written, &currentPosition, mOffset + t, mDuration);
         } else {
           FillWithZeroes(aOutput, channels, &written, &currentPosition, TRACK_TICKS_MAX);
         }
       }
     }
 
     // Process the gain on the AudioBufferSourceNode
     if (!aOutput->IsNull()) {