Bug 1308438 - Part 2: Support negative playback rate in ProcessBlock and add parameter aBufferMin to CopyFromBuffer's signature. r?dminor, r?padenot draft
authorBeekill95 <nnn_bikiu0707@yahoo.com>
Tue, 21 Mar 2017 22:04:42 +0700
changeset 502799 fb7641e07bad3ab775d9f10673eb3bd3574b43b7
parent 502798 1028d0fde2baf014941d4d6e1327b20e29f825da
child 502800 fc61f5cdec7657b7ec293e4e2cce6d02ac95617c
push id50409
push userbmo:nnn_bikiu0707@yahoo.com
push dateWed, 22 Mar 2017 11:28:53 +0000
reviewersdminor, padenot
bugs1308438
milestone54.0a1
Bug 1308438 - Part 2: Support negative playback rate in ProcessBlock and add parameter aBufferMin to CopyFromBuffer's signature. r?dminor, r?padenot MozReview-Commit-ID: 36wLB5rQgUp
dom/media/webaudio/AudioBufferSourceNode.cpp
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -151,16 +151,19 @@ public:
 
   bool BegunResampling()
   {
     return mBeginProcessing == -STREAM_TIME_MAX;
   }
 
   void UpdateResampler(int32_t aOutRate, uint32_t aChannels)
   {
+    // Only work with non negative aOutRate
+    aOutRate = std::abs(aOutRate);
+
     if (mResampler &&
         (aChannels != mChannels ||
          // If the resampler has begun, then it will have moved
          // mBufferPosition to after the samples it has read, but it hasn't
          // output its buffered samples.  Keep using the resampler, even if
          // the rates now match, so that this latent segment is output.
          (aOutRate == mBufferSampleRate && !BegunResampling()))) {
       speex_resampler_destroy(mResampler);
@@ -392,16 +395,17 @@ public:
    * 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(AudioBlock* aOutput,
                       uint32_t aChannels,
                       uint32_t* aOffsetWithinBlock,
                       StreamTime* aCurrentPosition,
+                      uint32_t aBufferMin,
                       uint32_t aBufferMax)
   {
     MOZ_ASSERT(*aCurrentPosition < mStop);
     uint32_t availableInOutput =
       std::min<StreamTime>(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                            mStop - *aCurrentPosition);
     if (mResampler) {
       CopyFromInputBufferWithResampling(aOutput, aChannels,
@@ -476,17 +480,17 @@ public:
     } else {
       playbackRate = mPlaybackRateTimeline.GetValueAtTime(aStreamPosition);
     }
     if (mDetuneTimeline.HasSimpleValue()) {
       detune = mDetuneTimeline.GetValue();
     } else {
       detune = mDetuneTimeline.GetValueAtTime(aStreamPosition);
     }
-    if (playbackRate <= 0 || mozilla::IsNaN(playbackRate)) {
+    if (mozilla::IsNaN(playbackRate)) {
       playbackRate = 1.0f;
     }
 
     detune = std::min(std::max(-1200.f, detune), 1200.f);
 
     int32_t outRate = ComputeFinalOutSampleRate(playbackRate, detune);
     UpdateResampler(outRate, aChannels);
   }
@@ -503,49 +507,57 @@ public:
       return;
     }
 
     StreamTime streamPosition = mDestination->GraphTimeToStreamTime(aFrom);
     uint32_t channels = mBuffer ? mBuffer->GetChannels() : 0;
 
     UpdateSampleRateIfNeeded(channels, streamPosition);
 
+    float playbackRate = mPlaybackRateTimeline.HasSimpleValue() ?
+                         mPlaybackRateTimeline.GetValue() :
+                         mPlaybackRateTimeline.GetValueAtTime(streamPosition);
     uint32_t written = 0;
     while (written < WEBAUDIO_BLOCK_SIZE) {
       if (mStop != STREAM_TIME_MAX &&
           streamPosition >= mStop) {
         FillWithZeroes(aOutput, channels, &written, &streamPosition, STREAM_TIME_MAX);
         continue;
       }
       if (streamPosition < mBeginProcessing) {
         FillWithZeroes(aOutput, channels, &written, &streamPosition,
                        mBeginProcessing);
         continue;
       }
       if (mLoop) {
         // mLoopEnd can become less than mBufferPosition when a LOOPEND engine
         // parameter is received after "loopend" is changed on the node or a
         // new buffer with lower samplerate is set.
-        if (mBufferPosition >= mLoopEnd) {
+        if (playbackRate >= 0 && mBufferPosition >= mLoopEnd) {
           mBufferPosition = mLoopStart;
+        } else if (playbackRate < 0 && mBufferPosition <= mLoopStart) {
+          mBufferPosition = mLoopEnd;
         }
-        CopyFromBuffer(aOutput, channels, &written, &streamPosition, mLoopEnd);
+        CopyFromBuffer(aOutput, channels, &written, &streamPosition, mLoopStart, mLoopEnd);
       } else {
-        if (mBufferPosition < mBufferEnd || mRemainingResamplerTail) {
-          CopyFromBuffer(aOutput, channels, &written, &streamPosition, mBufferEnd);
+        if ((playbackRate < 0 && mBufferPosition) ||
+            (playbackRate >= 0 && mBufferPosition < mBufferEnd) ||
+            mRemainingResamplerTail) {
+          CopyFromBuffer(aOutput, channels, &written, &streamPosition, 0, mBufferEnd);
         } else {
           FillWithZeroes(aOutput, channels, &written, &streamPosition, STREAM_TIME_MAX);
         }
       }
     }
 
     // We've finished if we've gone past mStop, or if we're past mDuration when
     // looping is disabled.
     if (streamPosition >= mStop ||
-        (!mLoop && mBufferPosition >= mBufferEnd && !mRemainingResamplerTail)) {
+        (playbackRate >= 0 && !mLoop && mBufferPosition >= mBufferEnd && !mRemainingResamplerTail) ||
+        (playbackRate < 0 && !mLoop && !mBufferPosition && !mRemainingResamplerTail)) {
       *aFinished = true;
     }
   }
 
   bool IsActive() const override
   {
     // Whether buffer has been set and start() has been called.
     return mBufferSampleRate != 0;