/**
  * Copy as many frames as possible from the source buffer to aOutput, and
  * advance aOffsetWithinBlock and aCurrentPosition based on how many frames
  * we write.  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(AudioNodeStream* aStream,
                     AudioChunk* aOutput,
                     uint32_t aChannels,
                     uint32_t* aOffsetWithinBlock,
                     TrackTicks* aCurrentPosition,
                     int32_t aBufferMax)
 {
   MOZ_ASSERT(*aCurrentPosition < mStop);
   uint32_t numFrames =
     std::min(std::min<TrackTicks>(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                                   aBufferMax - mBufferPosition),
              mStop - *aCurrentPosition);
   if (numFrames == WEBAUDIO_BLOCK_SIZE && !mResampler) {
     MOZ_ASSERT(mBufferPosition < aBufferMax);
     BorrowFromInputBuffer(aOutput, aChannels);
     *aOffsetWithinBlock += numFrames;
     *aCurrentPosition += numFrames;
     mBufferPosition += numFrames;
   } else {
     if (*aOffsetWithinBlock == 0) {
       AllocateAudioBlock(aChannels, aOutput);
     }
     if (!mResampler) {
       MOZ_ASSERT(mBufferPosition < aBufferMax);
       CopyFromInputBuffer(aOutput, aChannels, *aOffsetWithinBlock, numFrames);
       *aOffsetWithinBlock += numFrames;
       *aCurrentPosition += numFrames;
       mBufferPosition += numFrames;
     } else {
       CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aOffsetWithinBlock, aCurrentPosition, aBufferMax);
     }
   }
 }
  /**
   * 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(AudioNodeStream* aStream,
                      AudioChunk* aOutput,
                      uint32_t aChannels,
                      uint32_t* aOffsetWithinBlock,
                      TrackTicks* aCurrentPosition,
                      uint32_t aBufferOffset,
                      uint32_t aBufferMax)
  {
    MOZ_ASSERT(*aCurrentPosition < mStop);
    uint32_t numFrames =
      std::min<TrackTicks>(std::min(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                                    aBufferMax - aBufferOffset),
                           mStop - *aCurrentPosition);
    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(aStream->SampleRate())) {
        CopyFromInputBuffer(aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, numFrames);
        *aOffsetWithinBlock += numFrames;
        *aCurrentPosition += numFrames;
        mPosition += numFrames;
      } else {
        uint32_t framesRead, framesWritten, availableInInputBuffer;

        availableInInputBuffer = aBufferMax - aBufferOffset;

        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, availableInInputBuffer, framesRead, framesWritten);
        *aOffsetWithinBlock += framesWritten;
        *aCurrentPosition += framesRead;
        mPosition += framesRead;
      }
    }
  }