/** * 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; } } }
/** * 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(AudioBlock* aOutput, uint32_t aChannels, uint32_t* aOffsetWithinBlock, StreamTime* aCurrentPosition, uint32_t aBufferMax) { 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); 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 // attribute is reset after playback has looped. *aOffsetWithinBlock += availableInOutput; *aCurrentPosition += availableInOutput; // Rounding at the start and end of the period means that fractional // increments essentially accumulate if outRate remains constant. If // outRate is varying, then accumulation happens on average but not // precisely. TrackTicks start = *aCurrentPosition * mBufferSampleRate / mResamplerOutRate; TrackTicks end = (*aCurrentPosition + availableInOutput) * mBufferSampleRate / mResamplerOutRate; mBufferPosition += end - start; return; } uint32_t numFrames = std::min(aBufferMax - mBufferPosition, availableInOutput); bool shouldBorrow = false; if (numFrames == WEBAUDIO_BLOCK_SIZE && mBuffer.mBufferFormat == AUDIO_FORMAT_FLOAT32) { shouldBorrow = true; for (uint32_t i = 0; i < aChannels; ++i) { if (!IS_ALIGNED16(mBuffer.ChannelData<float>()[i] + mBufferPosition)) { shouldBorrow = false; break; } } } MOZ_ASSERT(mBufferPosition < aBufferMax); if (shouldBorrow) { BorrowFromInputBuffer(aOutput, aChannels); } else { if (*aOffsetWithinBlock == 0) { aOutput->AllocateChannels(aChannels); } if (mBuffer.mBufferFormat == AUDIO_FORMAT_FLOAT32) { CopyFromInputBuffer<float>(aOutput, aChannels, *aOffsetWithinBlock, numFrames); } else { MOZ_ASSERT(mBuffer.mBufferFormat == AUDIO_FORMAT_S16); CopyFromInputBuffer<int16_t>(aOutput, aChannels, *aOffsetWithinBlock, numFrames); } } *aOffsetWithinBlock += numFrames; *aCurrentPosition += numFrames; mBufferPosition += numFrames; }