Bug 1308438 - Part 4: Add parameter aBufferMin to CopyFromInputBufferWithResampling and modify the function to work with negative playback rate. r?dminor, r?padenot draft
authorBeekill95 <nnn_bikiu0707@yahoo.com>
Wed, 26 Apr 2017 10:34:14 +0700
changeset 569479 7ca93444fa7e6729430483d09ee1b6a150ad333f
parent 502800 fc61f5cdec7657b7ec293e4e2cce6d02ac95617c
child 569480 be60b28e6f4135920656fd5ca793699b43938a76
push id56194
push userbmo:nnn_bikiu0707@yahoo.com
push dateThu, 27 Apr 2017 15:03:23 +0000
reviewersdminor, padenot
bugs1308438
milestone54.0a1
Bug 1308438 - Part 4: Add parameter aBufferMin to CopyFromInputBufferWithResampling and modify the function to work with negative playback rate. r?dminor, r?padenot MozReview-Commit-ID: 3tAifLbFdPO
dom/media/webaudio/AudioBufferSourceNode.cpp
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -261,26 +261,34 @@ public:
   // 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(AudioBlock* aOutput,
                                          uint32_t aChannels,
                                          uint32_t* aOffsetWithinBlock,
                                          uint32_t aAvailableInOutput,
                                          StreamTime* aCurrentPosition,
+                                         uint32_t aBufferMin,
                                          uint32_t aBufferMax)
   {
     if (*aOffsetWithinBlock == 0) {
       aOutput->AllocateChannels(aChannels);
     }
     SpeexResamplerState* resampler = mResampler;
     MOZ_ASSERT(aChannels > 0);
 
-    if (mBufferPosition < aBufferMax) {
-      uint32_t availableInInputBuffer = aBufferMax - mBufferPosition;
+    float playbackRate = mPlaybackRateTimeline.HasSimpleValue() ?
+                         mPlaybackRateTimeline.GetValue() :
+                         mPlaybackRateTimeline.GetValueAtTime(*aCurrentPosition);
+
+    if ((playbackRate >= 0 && mBufferPosition < aBufferMax) ||
+        (playbackRate < 0 && mBufferPosition)) {
+      uint32_t availableInInputBuffer = playbackRate >= 0 ?
+                                        aBufferMax - mBufferPosition :
+                                        mBufferPosition - aBufferMin;
       uint32_t ratioNum, ratioDen;
       speex_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
       // Limit the number of input samples copied and possibly
       // format-converted for resampling by estimating how many will be used.
       // This may be a little small if still filling the resampler with
       // initial data, but we'll get called again and it will work out.
       uint32_t inputLimit = aAvailableInOutput * ratioNum / ratioDen + 10;
       if (!BegunResampling()) {
@@ -302,30 +310,47 @@ public:
           skipFracNum -= leadSubsamples;
         }
         speex_resampler_set_skip_frac_num(resampler,
                                   std::min<int64_t>(skipFracNum, UINT32_MAX));
 
         mBeginProcessing = -STREAM_TIME_MAX;
       }
       inputLimit = std::min(inputLimit, availableInInputBuffer);
+      inputLimit = std::min(inputLimit, WEBAUDIO_BLOCK_SIZE);
 
+      float bufferDataReversed[WEBAUDIO_BLOCK_SIZE];
       for (uint32_t i = 0; true; ) {
         uint32_t inSamples = inputLimit;
-        const float* inputData = mBuffer->GetData(i) + mBufferPosition;
+        const float* inputData;
+        if (playbackRate >= 0) {
+          inputData = mBuffer->GetData(i) + mBufferPosition;
+        } else {
+          const float* bufferData = mBuffer->GetData(i);
+          for (uint32_t i = 0; i < inSamples; ++i) {
+            bufferDataReversed[i] = bufferData[mBufferPosition - i - 1];
+          }
+          inputData = bufferDataReversed;
+        }
+
 
         uint32_t outSamples = aAvailableInOutput;
         float* outputData =
           aOutput->ChannelFloatsForWrite(i) + *aOffsetWithinBlock;
 
         WebAudioUtils::SpeexResamplerProcess(resampler, i,
                                              inputData, &inSamples,
                                              outputData, &outSamples);
         if (++i == aChannels) {
-          mBufferPosition += inSamples;
+          if (playbackRate >= 0) {
+            mBufferPosition += inSamples;
+          } else {
+            MOZ_ASSERT(inSamples <= mBufferPosition);
+            mBufferPosition -= inSamples;
+          }
           MOZ_ASSERT(mBufferPosition <= mBufferEnd || mLoop);
           *aOffsetWithinBlock += outSamples;
           *aCurrentPosition += outSamples;
           if (inSamples == availableInInputBuffer && !mLoop) {
             // We'll feed in enough zeros to empty out the resampler's memory.
             // This handles the output latency as well as capturing the low
             // pass effects of the resample filter.
             mRemainingResamplerTail =
@@ -405,17 +430,17 @@ public:
   {
     MOZ_ASSERT(*aCurrentPosition < mStop);
     uint32_t availableInOutput =
       std::min<StreamTime>(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                            mStop - *aCurrentPosition);
     if (mResampler) {
       CopyFromInputBufferWithResampling(aOutput, aChannels,
                                         aOffsetWithinBlock, availableInOutput,
-                                        aCurrentPosition, aBufferMax);
+                                        aCurrentPosition, aBufferMin, aBufferMax);
       return;
     }
 
     if (aChannels == 0) {
       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
       // There is no attempt here to limit advance so that mBufferPosition is
       // limited to aBufferMax.  The only observable affect of skipping the
       // check would be in the precise timing of the ended event if the loop