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(aStream->SampleRate()) == 0) { mPlaybackRate = 1.0; mDopplerShift = 1.0; } uint32_t currentOutSampleRate, currentInSampleRate; if (ShouldResample(aStream->SampleRate())) { SpeexResamplerState* resampler = Resampler(aStream, aChannels); speex_resampler_get_rate(resampler, ¤tInSampleRate, ¤tOutSampleRate); uint32_t finalSampleRate = ComputeFinalOutSampleRate(aStream->SampleRate()); if (currentOutSampleRate != finalSampleRate) { speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate); } } }
/** * 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(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 && !ShouldResample(aStream->SampleRate())) { MOZ_ASSERT(mBufferPosition < aBufferMax); BorrowFromInputBuffer(aOutput, aChannels); *aOffsetWithinBlock += numFrames; *aCurrentPosition += numFrames; mBufferPosition += numFrames; } else { if (*aOffsetWithinBlock == 0) { AllocateAudioBlock(aChannels, aOutput); } if (!ShouldResample(aStream->SampleRate())) { MOZ_ASSERT(mBufferPosition < aBufferMax); CopyFromInputBuffer(aOutput, aChannels, *aOffsetWithinBlock, numFrames); *aOffsetWithinBlock += numFrames; *aCurrentPosition += numFrames; mBufferPosition += numFrames; } else { uint32_t framesWritten; CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, *aOffsetWithinBlock, framesWritten, aBufferMax); *aOffsetWithinBlock += framesWritten; *aCurrentPosition += framesWritten; } } }